Skip to content

Commit 9fc5170

Browse files
authored
parse modules, other parser improvements (#29)
Parse plus basic constraints.
1 parent d6330a5 commit 9fc5170

34 files changed

+667
-122
lines changed

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"deno.enable": true,
3+
"debug.javascript.autoAttachFilter": "onlyWithFlag",
4+
"deno.codeLens.test": true
5+
}

deno.lock

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,14 @@ export {
5555
type TypeDefinition,
5656
} from "./meta/trip.ts";
5757
export { externalReferences } from "./meta/frontend/externalReferences.ts";
58-
export { indexSymbols, resolveDefTerm } from "./meta/frontend/symbolTable.ts";
59-
export { resolveRefs } from "./meta/frontend/substitution.ts";
58+
export {
59+
extractDefinitionValue,
60+
indexSymbols,
61+
} from "./meta/frontend/symbolTable.ts";
62+
export {
63+
resolveExternalProgramReferences,
64+
resolveExternalTermReferences,
65+
} from "./meta/frontend/substitution.ts";
6066

6167
// Additional utility exports
6268
export { UnChurchNumber } from "./ski/church.ts";

lib/meta/frontend/compilation.ts

Lines changed: 121 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1-
import type { SymbolTable, TripLangProgram, TripLangTerm } from "../trip.ts";
1+
import type {
2+
SymbolTable,
3+
TripLangProgram,
4+
TripLangTerm,
5+
TripLangValueType,
6+
} from "../trip.ts";
27
import {
8+
extractDefinitionValue,
39
indexSymbols as indexSymbolsImpl,
4-
resolveDefTerm,
510
} from "./symbolTable.ts";
611
import { elaborateTerms } from "./elaboration.ts";
7-
import { resolveRefs } from "./substitution.ts";
12+
import { resolveExternalProgramReferences } from "./substitution.ts";
813
import { externalReferences } from "./externalReferences.ts";
914
import {
1015
type AVLTree,
1116
createEmptyAVL,
12-
emptyAVL,
1317
insertAVL,
18+
keyValuePairs,
19+
searchAVL,
1420
} from "../../data/avl/avlNode.ts";
1521
import { parseTripLang } from "../../parser/tripLang.ts";
1622
import { typecheckSystemF } from "../../index.ts";
@@ -104,6 +110,27 @@ export interface TypecheckedProgramWithTypes {
104110

105111
export function parse(input: string): ParsedProgram {
106112
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+
107134
return { ...program, __moniker: Symbol() } as ParsedProgram;
108135
}
109136

@@ -137,19 +164,77 @@ export function elaborate(
137164
export function resolve(
138165
programWithSymbols: ElaboratedProgramWithSymbols,
139166
): 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(
141176
programWithSymbols.program,
142177
programWithSymbols.symbols,
143178
);
144179

145180
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+
149230
throw new CompilationError(
150231
"Unresolved external references after resolution",
151232
"resolve",
152-
{ term: resolvedTerm, unresolvedTerms: ut, unresolvedTypes: uty },
233+
{
234+
term: resolvedTerm,
235+
unresolvedTerms: filteredTerms,
236+
unresolvedTypes: filteredTypes,
237+
},
153238
);
154239
}
155240
}
@@ -160,10 +245,37 @@ export function resolve(
160245
export function typecheck(
161246
program: ResolvedProgram,
162247
): 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+
163256
let types = createEmptyAVL<string, BaseType>();
164257

165258
for (const term of program.terms) {
166259
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+
167279
switch (term.kind) {
168280
case "poly":
169281
types = insertAVL(

lib/meta/frontend/elaboration.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ export function elaborateTerm(
3838
return term;
3939
case "type":
4040
return term;
41+
case "module":
42+
return term;
43+
case "import":
44+
return term;
45+
case "export":
46+
return term;
4147
}
4248
}
4349

lib/meta/frontend/externalReferences.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ import {
66
} from "../../data/avl/avlNode.ts";
77
import { compareStrings } from "../../data/map/stringMap.ts";
88
import type { BaseType } from "../../types/types.ts";
9-
import type { TripLangDefType } from "../trip.ts";
9+
import type { TripLangValueType } from "../trip.ts";
1010
import { CompilationError } from "./compilation.ts";
1111

12-
export function externalReferences(td: TripLangDefType): [
13-
AVLTree<string, TripLangDefType>,
12+
export function externalReferences(td: TripLangValueType): [
13+
AVLTree<string, TripLangValueType>,
1414
AVLTree<string, BaseType>,
1515
] {
16-
let externalTermRefs = createEmptyAVL<string, TripLangDefType>();
16+
let externalTermRefs = createEmptyAVL<string, TripLangValueType>();
1717
let externalTypeRefs = createEmptyAVL<string, BaseType>();
18-
let absBindMap = createEmptyAVL<string, TripLangDefType>();
19-
const defStack: TripLangDefType[] = [td];
18+
let absBindMap = createEmptyAVL<string, TripLangValueType>();
19+
const defStack: TripLangValueType[] = [td];
2020

2121
while (defStack.length) {
2222
const current = defStack.pop();

lib/meta/frontend/prettyPrint.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,11 @@ export function prettyTerm(dt: TripLangTerm): string {
1919
return dt.name + def + prettyPrintSKI(dt.term);
2020
case "type":
2121
return dt.name + def + prettyPrintTy(dt.type);
22+
case "module":
23+
return `module ${dt.name}`;
24+
case "import":
25+
return `import ${dt.name} from ${dt.ref}`;
26+
case "export":
27+
return `export ${dt.name}`;
2228
}
2329
}

0 commit comments

Comments
 (0)