-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnames.ts
154 lines (130 loc) · 3.78 KB
/
names.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import * as Colors from "https://deno.land/[email protected]/fmt/colors.ts";
import { Stack } from "./stack.ts";
import { Context, format_location, State } from "./tsgen.ts";
import { Location } from "./get_current_line.ts";
import { current_path } from "./out.ts";
export type PerNameState = State;
const statekey = Symbol("Names");
const location_key = Symbol("CreationLocation");
const kind_key = Symbol("Kind");
const output_file_key = Symbol("OutputFile");
interface NamesState {
names: Map<string, PerNameState>;
}
function names_state(ctx: Context): NamesState {
const state = ctx.state.get(statekey);
if (state) {
return <NamesState> state;
} else {
ctx.state.set(statekey, {
names: new Map(),
});
return names_state(ctx);
}
}
export function get_name_location(pns: PerNameState): Stack<Location> {
return <Stack<Location>> pns.get(location_key)!;
}
export function get_name_kind(pns: PerNameState): string {
return <string> pns.get(kind_key)!;
}
export function get_output_file(pns: PerNameState): string[] {
return <string[]> pns.get(output_file_key)!;
}
export function new_name(
name: string,
kind: string,
ctx: Context,
is_unsafe_name?: boolean,
): PerNameState | null {
const safe_name_regex = /^[A-Za-z][A-Za-z0-9_]*$/;
if (!is_unsafe_name && !safe_name_regex.test(name)) {
ctx.error(`Invalid name ${style_name(name)} at ${format_location(ctx.stack.peek()!)}`);
ctx.error(" Names must match regex /^[A-Za-z][A-Za-z0-9_]*$/");
ctx.halt();
return null;
}
const names = names_state(ctx).names;
const existing_name = names.get(name);
if (existing_name != undefined) {
ctx.error(
`Cannot create name ${
style_name(name)
}, there already exists a conflicting name.`,
);
ctx.error(
` The conflicting name was created by ${
format_location(get_name_location(existing_name).peek()!)
}`,
);
ctx.halt();
return null;
}
const per_name_state = new Map();
names.set(name, per_name_state);
per_name_state.set(location_key, ctx.stack);
per_name_state.set(kind_key, kind);
per_name_state.set(output_file_key, [...current_path(ctx)]);
return per_name_state;
}
export function try_resolve_name(
name: string,
expected_kind: string,
ctx: Context,
): PerNameState | undefined {
const name_state = try_resolve_name_any(name, ctx);
if (name_state) {
const kind = get_name_kind(name_state);
if (kind === expected_kind) {
return name_state;
} else {
ctx.error(`Expected name ${style_name(name)} to be of kind ${style_name_kind(expected_kind)}, but it was of kind ${style_name_kind(kind)}.`);
ctx.error(` The name was created by ${format_location(get_name_location(name_state).peek()!)}`);
ctx.halt();
return undefined;
}
} else {
return undefined;
}
}
export function resolve_name(
name: string,
expected_kind: string,
ctx: Context,
): PerNameState | null {
const name_state = try_resolve_name(name, expected_kind, ctx);
if (name_state === undefined) {
if (!ctx.did_halt()) {
ctx.error(`Name ${style_name(name)} is undefined.`);
ctx.halt();
}
return null;
} else {
return name_state;
}
}
export function try_resolve_name_any(
name: string,
ctx: Context,
): PerNameState | undefined {
return names_state(ctx).names.get(name);
}
export function resolve_name_any(
name: string,
ctx: Context,
): PerNameState | null {
const name_state = try_resolve_name_any(name, ctx);
if (name_state === undefined) {
ctx.error(`Name ${style_name(name)} is undefined.`);
ctx.halt();
return null;
} else {
return name_state;
}
}
export function style_name(s: string): string {
return Colors.cyan(s);
}
export function style_name_kind(s: string): string {
return Colors.magenta(s);
}