1
- import type { SymbolTable , TripLangProgram , TripLangTerm } from "../trip.ts" ;
1
+ import type {
2
+ SymbolTable ,
3
+ TripLangProgram ,
4
+ TripLangTerm ,
5
+ TripLangValueType ,
6
+ } from "../trip.ts" ;
2
7
import {
8
+ extractDefinitionValue ,
3
9
indexSymbols as indexSymbolsImpl ,
4
- resolveDefTerm ,
5
10
} from "./symbolTable.ts" ;
6
11
import { elaborateTerms } from "./elaboration.ts" ;
7
- import { resolveRefs } from "./substitution.ts" ;
12
+ import { resolveExternalProgramReferences } from "./substitution.ts" ;
8
13
import { externalReferences } from "./externalReferences.ts" ;
9
14
import {
10
15
type AVLTree ,
11
16
createEmptyAVL ,
12
- emptyAVL ,
13
17
insertAVL ,
18
+ keyValuePairs ,
19
+ searchAVL ,
14
20
} from "../../data/avl/avlNode.ts" ;
15
21
import { parseTripLang } from "../../parser/tripLang.ts" ;
16
22
import { typecheckSystemF } from "../../index.ts" ;
@@ -104,6 +110,27 @@ export interface TypecheckedProgramWithTypes {
104
110
105
111
export function parse ( input : string ) : ParsedProgram {
106
112
const program = parseTripLang ( input ) ;
113
+
114
+ // Validate module constraints
115
+ const moduleDefinitions = program . terms . filter ( ( term ) =>
116
+ term . kind === "module"
117
+ ) ;
118
+
119
+ if ( moduleDefinitions . length === 0 ) {
120
+ throw new CompilationError (
121
+ "No module definition found. Each program must have exactly one module definition." ,
122
+ "parse" ,
123
+ ) ;
124
+ }
125
+
126
+ if ( moduleDefinitions . length > 1 ) {
127
+ const moduleNames = moduleDefinitions . map ( ( m ) => m . name ) . join ( ", " ) ;
128
+ throw new CompilationError (
129
+ `Multiple module definitions found: ${ moduleNames } . Each program must have exactly one module definition.` ,
130
+ "parse" ,
131
+ ) ;
132
+ }
133
+
107
134
return { ...program , __moniker : Symbol ( ) } as ParsedProgram ;
108
135
}
109
136
@@ -137,19 +164,77 @@ export function elaborate(
137
164
export function resolve (
138
165
programWithSymbols : ElaboratedProgramWithSymbols ,
139
166
) : ResolvedProgram {
140
- const resolved = resolveRefs (
167
+ // Collect imported symbol names
168
+ const importedSymbols = new Set < string > ( ) ;
169
+ for ( const term of programWithSymbols . program . terms ) {
170
+ if ( term . kind === "import" ) {
171
+ importedSymbols . add ( term . name ) ;
172
+ }
173
+ }
174
+
175
+ const resolved = resolveExternalProgramReferences (
141
176
programWithSymbols . program ,
142
177
programWithSymbols . symbols ,
143
178
) ;
144
179
145
180
for ( const resolvedTerm of resolved . terms ) {
146
- const defTerm = resolveDefTerm ( resolvedTerm ) ;
147
- const [ ut , uty ] = externalReferences ( defTerm ) ;
148
- if ( ! emptyAVL ( ut ) || ! emptyAVL ( uty ) ) {
181
+ const definitionValue = extractDefinitionValue ( resolvedTerm ) ;
182
+ if ( definitionValue === undefined ) {
183
+ continue ;
184
+ }
185
+ const [ ut , uty ] = externalReferences ( definitionValue ) ;
186
+
187
+ // Check for unresolved terms that are not imported
188
+ const unresolvedTerms = keyValuePairs ( ut ) . map ( ( kvp ) => kvp [ 0 ] ) ;
189
+ const unresolvedTypes = keyValuePairs ( uty ) . map ( ( kvp ) => kvp [ 0 ] ) ;
190
+
191
+ const nonImportedUnresolvedTerms = unresolvedTerms . filter ( ( term ) =>
192
+ ! importedSymbols . has ( term )
193
+ ) ;
194
+ const nonImportedUnresolvedTypes = unresolvedTypes . filter ( ( type ) =>
195
+ ! importedSymbols . has ( type )
196
+ ) ;
197
+
198
+ if (
199
+ nonImportedUnresolvedTerms . length > 0 ||
200
+ nonImportedUnresolvedTypes . length > 0
201
+ ) {
202
+ // Create filtered AVL trees with only non-imported unresolved references
203
+ let filteredTerms = createEmptyAVL < string , TripLangValueType > ( ) ;
204
+ let filteredTypes = createEmptyAVL < string , BaseType > ( ) ;
205
+
206
+ for ( const term of nonImportedUnresolvedTerms ) {
207
+ const termValue = searchAVL ( ut , term , compareStrings ) ;
208
+ if ( termValue ) {
209
+ filteredTerms = insertAVL (
210
+ filteredTerms ,
211
+ term ,
212
+ termValue ,
213
+ compareStrings ,
214
+ ) ;
215
+ }
216
+ }
217
+
218
+ for ( const type of nonImportedUnresolvedTypes ) {
219
+ const typeValue = searchAVL ( uty , type , compareStrings ) ;
220
+ if ( typeValue ) {
221
+ filteredTypes = insertAVL (
222
+ filteredTypes ,
223
+ type ,
224
+ typeValue ,
225
+ compareStrings ,
226
+ ) ;
227
+ }
228
+ }
229
+
149
230
throw new CompilationError (
150
231
"Unresolved external references after resolution" ,
151
232
"resolve" ,
152
- { term : resolvedTerm , unresolvedTerms : ut , unresolvedTypes : uty } ,
233
+ {
234
+ term : resolvedTerm ,
235
+ unresolvedTerms : filteredTerms ,
236
+ unresolvedTypes : filteredTypes ,
237
+ } ,
153
238
) ;
154
239
}
155
240
}
@@ -160,10 +245,37 @@ export function resolve(
160
245
export function typecheck (
161
246
program : ResolvedProgram ,
162
247
) : TypecheckedProgramWithTypes {
248
+ // Collect imported symbol names
249
+ const importedSymbols = new Set < string > ( ) ;
250
+ for ( const term of program . terms ) {
251
+ if ( term . kind === "import" ) {
252
+ importedSymbols . add ( term . name ) ;
253
+ }
254
+ }
255
+
163
256
let types = createEmptyAVL < string , BaseType > ( ) ;
164
257
165
258
for ( const term of program . terms ) {
166
259
try {
260
+ // Check if the term contains unresolved imported symbols
261
+ const definitionValue = extractDefinitionValue ( term ) ;
262
+ if ( definitionValue !== undefined ) {
263
+ const [ ut , uty ] = externalReferences ( definitionValue ) ;
264
+ const unresolvedTerms = keyValuePairs ( ut ) . map ( ( kvp ) => kvp [ 0 ] ) ;
265
+ const unresolvedTypes = keyValuePairs ( uty ) . map ( ( kvp ) => kvp [ 0 ] ) ;
266
+
267
+ // Check if any unresolved references are imported symbols
268
+ const hasUnresolvedImportedSymbols = unresolvedTerms . some ( ( term ) =>
269
+ importedSymbols . has ( term )
270
+ ) ||
271
+ unresolvedTypes . some ( ( type ) => importedSymbols . has ( type ) ) ;
272
+
273
+ if ( hasUnresolvedImportedSymbols ) {
274
+ // Skip typechecking for terms with unresolved imported symbols
275
+ continue ;
276
+ }
277
+ }
278
+
167
279
switch ( term . kind ) {
168
280
case "poly" :
169
281
types = insertAVL (
0 commit comments