@harmoniclabs/pebble 0.1.3-dev3 → 0.1.3-dev6

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.
@@ -44,7 +44,7 @@ export function _compileSimpleVarDecl(ctx, decl, typeHint) {
44
44
  const typeAndExpr = _getVarDeclTypeAndExpr(ctx, decl, typeHint);
45
45
  if (!typeAndExpr)
46
46
  return undefined;
47
- const [finalVarType, initExpr] = typeAndExpr;
47
+ const [finalVarType, initExpr, typeAnnotationRange] = typeAndExpr;
48
48
  const success = ctx.scope.defineValue({
49
49
  name: decl.name.text,
50
50
  type: finalVarType,
@@ -52,7 +52,7 @@ export function _compileSimpleVarDecl(ctx, decl, typeHint) {
52
52
  });
53
53
  if (!success)
54
54
  return ctx.error(DiagnosticCode.Duplicate_identifier_0, decl.name.range, decl.name.text);
55
- return new TirSimpleVarDecl(decl.name.text, finalVarType, initExpr, decl.isConst(), decl.range);
55
+ return new TirSimpleVarDecl(decl.name.text, finalVarType, initExpr, decl.isConst(), decl.range, typeAnnotationRange, decl.sourceName);
56
56
  }
57
57
  export function _compileNamedDeconstructVarDecl(ctx, decl, typeHint) {
58
58
  // const Spending{ ref, optionalDatum: datum as MyDatum } = purpose
@@ -71,7 +71,7 @@ export function _compileNamedDeconstructVarDecl(ctx, decl, typeHint) {
71
71
  const typeAndExpr = _getVarDeclTypeAndExpr(ctx, decl, typeHint);
72
72
  if (!typeAndExpr)
73
73
  return undefined;
74
- const [finalVarType, initExpr] = typeAndExpr;
74
+ const [finalVarType, initExpr, typeAnnotationRange] = typeAndExpr;
75
75
  const namedDestructableType = getNamedDestructableType(finalVarType);
76
76
  if (!namedDestructableType
77
77
  || !namedDestructableType.isConcrete())
@@ -86,8 +86,8 @@ export function _compileNamedDeconstructVarDecl(ctx, decl, typeHint) {
86
86
  ] : []));
87
87
  if (!deconstructedFields)
88
88
  return undefined;
89
- const [fieds, rest] = deconstructedFields;
90
- return new TirNamedDeconstructVarDecl(decl.name.text, fieds, rest, finalVarType, initExpr, decl.isConst(), decl.range);
89
+ const [fieds, rest, fieldLabelRanges] = deconstructedFields;
90
+ return new TirNamedDeconstructVarDecl(decl.name.text, fieds, rest, finalVarType, initExpr, decl.isConst(), decl.range, decl.name.range, fieldLabelRanges, typeAnnotationRange);
91
91
  }
92
92
  if (isTirStructType(namedDestructableType)) {
93
93
  const finalConstructorDef = namedDestructableType.constructors.find(ctor => ctor.name === decl.name.text);
@@ -96,15 +96,15 @@ export function _compileNamedDeconstructVarDecl(ctx, decl, typeHint) {
96
96
  const deconstructedFields = _getDeconstructedFields(ctx, decl, finalConstructorDef);
97
97
  if (!deconstructedFields)
98
98
  return undefined;
99
- const [fieds, rest] = deconstructedFields;
100
- return new TirNamedDeconstructVarDecl(decl.name.text, fieds, rest, finalVarType, initExpr, decl.isConst(), decl.range);
99
+ const [fieds, rest, fieldLabelRanges] = deconstructedFields;
100
+ return new TirNamedDeconstructVarDecl(decl.name.text, fieds, rest, finalVarType, initExpr, decl.isConst(), decl.range, decl.name.range, fieldLabelRanges, typeAnnotationRange);
101
101
  }
102
102
  }
103
103
  export function _compileSingleDeconstructVarDecl(ctx, decl, typeHint) {
104
104
  const typeAndExpr = _getVarDeclTypeAndExpr(ctx, decl, typeHint);
105
105
  if (!typeAndExpr)
106
106
  return undefined;
107
- const [finalVarType, initExpr] = typeAndExpr;
107
+ const [finalVarType, initExpr, typeAnnotationRange] = typeAndExpr;
108
108
  const finalStructType = getStructType(finalVarType);
109
109
  if (!finalStructType)
110
110
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, decl.range, finalVarType.toString(), "Struct");
@@ -113,14 +113,14 @@ export function _compileSingleDeconstructVarDecl(ctx, decl, typeHint) {
113
113
  const deconstructedFields = _getDeconstructedFields(ctx, decl, finalStructType.constructors[0]);
114
114
  if (!deconstructedFields)
115
115
  return undefined;
116
- const [fieds, rest] = deconstructedFields;
117
- return new TirSingleDeconstructVarDecl(fieds, rest, finalVarType, initExpr, decl.isConst(), decl.range);
116
+ const [fieds, rest, fieldLabelRanges] = deconstructedFields;
117
+ return new TirSingleDeconstructVarDecl(fieds, rest, finalVarType, initExpr, decl.isConst(), decl.range, fieldLabelRanges, typeAnnotationRange);
118
118
  }
119
119
  export function _compileArrayLikeDeconstr(ctx, decl, typeHint) {
120
120
  const typeAndExpr = _getVarDeclTypeAndExpr(ctx, decl, typeHint);
121
121
  if (!typeAndExpr)
122
122
  return undefined;
123
- const [finalVarType, initExpr] = typeAndExpr;
123
+ const [finalVarType, initExpr, _typeAnnotationRange] = typeAndExpr;
124
124
  const elemsType = getListTypeArg(finalVarType);
125
125
  if (!elemsType)
126
126
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, decl.range, finalVarType.toString(), "List");
@@ -146,6 +146,7 @@ export function _compileArrayLikeDeconstr(ctx, decl, typeHint) {
146
146
  }
147
147
  export function _getDeconstructedFields(ctx, astDeconstruct, ctorDef) {
148
148
  const tirFields = new Map();
149
+ const fieldLabelRanges = new Map();
149
150
  const ctorDefFieldNames = ctorDef.fields.map(f => f.name);
150
151
  const ctorNamesAlreadySpecified = [];
151
152
  for (const [fieldIdentifier, varDecl] of astDeconstruct.fields) {
@@ -155,8 +156,10 @@ export function _getDeconstructedFields(ctx, astDeconstruct, ctorDef) {
155
156
  if (ctorNamesAlreadySpecified.includes(fieldName))
156
157
  return ctx.error(DiagnosticCode.Duplicate_identifier_0, fieldIdentifier.range, fieldName);
157
158
  ctorNamesAlreadySpecified.push(fieldName);
159
+ const ctorFieldType = ctorDef.fields.find(f => f.name === fieldName).type;
160
+ fieldLabelRanges.set(fieldName, { range: fieldIdentifier.range, type: ctorFieldType });
158
161
  // adds to scope "simple" var decls
159
- const tirVarDecl = _compileVarDecl(ctx, varDecl, ctorDef.fields.find(f => f.name === fieldName).type);
162
+ const tirVarDecl = _compileVarDecl(ctx, varDecl, ctorFieldType);
160
163
  if (!tirVarDecl)
161
164
  return undefined;
162
165
  tirFields.set(fieldName, tirVarDecl);
@@ -164,7 +167,7 @@ export function _getDeconstructedFields(ctx, astDeconstruct, ctorDef) {
164
167
  if (astDeconstruct.rest && ctorDefFieldNames.length === ctorNamesAlreadySpecified.length)
165
168
  return ctx.error(DiagnosticCode.Invalid_rest_parameter_there_are_no_more_fields, astDeconstruct.rest.range);
166
169
  let rest = astDeconstruct.rest ? astDeconstruct.rest.text : undefined;
167
- return [tirFields, rest];
170
+ return [tirFields, rest, fieldLabelRanges];
168
171
  }
169
172
  export function _getVarDeclTypeAndExpr(ctx, decl, deconstructTypeHint) {
170
173
  const declarationType = decl.type ? _compileSopEncodedConcreteType(ctx, decl.type) : undefined;
@@ -204,5 +207,5 @@ export function _getVarDeclTypeAndExpr(ctx, decl, deconstructTypeHint) {
204
207
  const finalVarType = typeHint ?? initExpr?.type;
205
208
  if (!finalVarType)
206
209
  return ctx.error(DiagnosticCode.Cannot_infer_variable_type_Try_to_make_the_type_explicit, decl.range);
207
- return [finalVarType, initExpr];
210
+ return [finalVarType, initExpr, decl.type?.range];
208
211
  }
@@ -2,10 +2,13 @@ import { DiagnosticEmitter } from "../diagnostics/DiagnosticEmitter.js";
2
2
  import { DiagnosticMessage } from "../diagnostics/DiagnosticMessage.js";
3
3
  import { CompilerOptions } from "../IR/toUPLC/CompilerOptions.js";
4
4
  import { CompilerIoApi } from "./io/CompilerIoApi.js";
5
+ import { CheckResult } from "./SourceTypeMap.js";
6
+ export { CheckResult, SourceTypeMap, TypeEntry, MemberInfo } from "./SourceTypeMap.js";
5
7
  export declare class Compiler extends DiagnosticEmitter {
6
8
  readonly io: CompilerIoApi;
7
9
  readonly cfg: CompilerOptions;
8
10
  constructor(io?: CompilerIoApi, cfg?: CompilerOptions, diagnostics?: DiagnosticMessage[]);
11
+ check(config?: Partial<CompilerOptions>): Promise<CheckResult>;
9
12
  compile(config?: Partial<CompilerOptions>): Promise<Uint8Array>;
10
13
  export(config: Partial<ExportOptions> & HasFuncitonName): Promise<Uint8Array>;
11
14
  run(config?: Partial<CompilerOptions>): Promise<{
@@ -13,6 +16,11 @@ export declare class Compiler extends DiagnosticEmitter {
13
16
  budgetSpent: import("@harmoniclabs/plutus-machine").ExBudget;
14
17
  logs: string[];
15
18
  }>;
19
+ runRepl(config?: Partial<CompilerOptions>): Promise<{
20
+ result: import("@harmoniclabs/plutus-machine").CEKValueObj;
21
+ budgetSpent: import("@harmoniclabs/plutus-machine").ExBudget;
22
+ logs: string[];
23
+ }>;
16
24
  private _compileBackend;
17
25
  }
18
26
  interface HasFuncitonName {
@@ -20,4 +28,3 @@ interface HasFuncitonName {
20
28
  }
21
29
  export interface ExportOptions extends CompilerOptions, HasFuncitonName {
22
30
  }
23
- export {};
@@ -7,6 +7,7 @@ import { createMemoryCompilerIoApi } from "./io/CompilerIoApi.js";
7
7
  import { compileTypedProgram } from "./TirCompiler/compileTirProgram.js";
8
8
  import { __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION } from "../IR/IRHash.js";
9
9
  import { compileIRToUPLC } from "../IR/toUPLC/compileIRToUPLC.js";
10
+ export { SourceTypeMap } from "./SourceTypeMap.js";
10
11
  export class Compiler extends DiagnosticEmitter {
11
12
  io;
12
13
  cfg;
@@ -18,6 +19,15 @@ export class Compiler extends DiagnosticEmitter {
18
19
  this.io.stdout = { write() { } };
19
20
  }
20
21
  }
22
+ async check(config) {
23
+ const cfg = {
24
+ ...this.cfg,
25
+ ...config,
26
+ silent: true,
27
+ };
28
+ const astCompiler = new AstCompiler(cfg, this.io, this.diagnostics);
29
+ return await astCompiler.check();
30
+ }
21
31
  async compile(config) {
22
32
  const cfg = {
23
33
  ...this.cfg,
@@ -30,9 +40,10 @@ export class Compiler extends DiagnosticEmitter {
30
40
  globalThis.console && console.log(this.diagnostics);
31
41
  const fstErrorMsg = this.diagnostics[0].toString();
32
42
  const nDiags = this.diagnostics.length;
33
- while (msg = this.diagnostics.shift()) {
43
+ for (msg of this.diagnostics) {
34
44
  this.io.stdout.write(msg.toString() + "\n");
35
45
  }
46
+ // return new Uint8Array();
36
47
  throw new Error("compilation failed with " + nDiags + " diagnostic messages; first message: " + fstErrorMsg);
37
48
  }
38
49
  return this._compileBackend(cfg, program);
@@ -84,6 +95,28 @@ export class Compiler extends DiagnosticEmitter {
84
95
  const uplcProgram = parseUPLC(serialized);
85
96
  return Machine.eval(uplcProgram.body);
86
97
  }
98
+ async runRepl(config) {
99
+ const cfg = {
100
+ ...this.cfg,
101
+ ...config,
102
+ addMarker: false,
103
+ };
104
+ const astCompiler = new AstCompiler(cfg, this.io, this.diagnostics);
105
+ const program = await astCompiler.runRepl();
106
+ if (this.diagnostics.length > 0) {
107
+ let msg;
108
+ globalThis.console && console.log(this.diagnostics);
109
+ const fstErrorMsg = this.diagnostics[0].toString();
110
+ const nDiags = this.diagnostics.length;
111
+ while (msg = this.diagnostics.shift()) {
112
+ this.io.stdout.write(msg.toString() + "\n");
113
+ }
114
+ throw new Error("compilation failed with " + nDiags + " diagnostic messages; first message: " + fstErrorMsg);
115
+ }
116
+ const serialized = this._compileBackend(cfg, program);
117
+ const uplcProgram = parseUPLC(serialized);
118
+ return Machine.eval(uplcProgram.body);
119
+ }
87
120
  _compileBackend(cfg, program) {
88
121
  // backend starts here
89
122
  const ir = compileTypedProgram(cfg, program);
@@ -0,0 +1,43 @@
1
+ import { DiagnosticMessage } from "../diagnostics/DiagnosticMessage.js";
2
+ import { TirType } from "./tir/types/TirType.js";
3
+ import { TypedProgram } from "./tir/program/TypedProgram.js";
4
+ export interface TypeEntry {
5
+ start: number;
6
+ end: number;
7
+ type: TirType;
8
+ name?: string;
9
+ /** "type-reference" marks constructor/type names; default is "expression" */
10
+ kind?: "expression" | "type-reference";
11
+ }
12
+ export interface MemberInfo {
13
+ name: string;
14
+ type: TirType;
15
+ kind: "field" | "method";
16
+ }
17
+ export interface CheckResult {
18
+ diagnostics: DiagnosticMessage[];
19
+ program: TypedProgram;
20
+ sourceTypeMap: SourceTypeMap;
21
+ }
22
+ export declare class SourceTypeMap {
23
+ readonly program: TypedProgram;
24
+ private entries;
25
+ private sorted;
26
+ constructor(program: TypedProgram);
27
+ buildFromProgram(): void;
28
+ private addEntry;
29
+ private ensureSorted;
30
+ typeAtOffset(offset: number): TypeEntry | undefined;
31
+ allEntries(): readonly TypeEntry[];
32
+ membersOfType(type: TirType): MemberInfo[];
33
+ private structMembers;
34
+ private methodsFromMap;
35
+ private listMembers;
36
+ private bytesMembers;
37
+ private stringMembers;
38
+ private linearMapMembers;
39
+ private walkFuncExpr;
40
+ private walkExpr;
41
+ private walkStmt;
42
+ private walkVarDecl;
43
+ }
@@ -0,0 +1,432 @@
1
+ import { isInternalName } from "./internalVar.js";
2
+ import { TirAliasType } from "./tir/types/TirAliasType.js";
3
+ import { isTirStructType } from "./tir/types/TirStructType.js";
4
+ import { TirFuncT } from "./tir/types/TirNativeType/native/function.js";
5
+ import { TirListT } from "./tir/types/TirNativeType/native/list.js";
6
+ import { TirLinearMapT } from "./tir/types/TirNativeType/native/linearMap.js";
7
+ import { TirBytesT } from "./tir/types/TirNativeType/native/bytes.js";
8
+ import { TirStringT } from "./tir/types/TirNativeType/native/string.js";
9
+ import { TirBoolT } from "./tir/types/TirNativeType/native/bool.js";
10
+ import { TirIntT } from "./tir/types/TirNativeType/native/int.js";
11
+ import { TirDataT } from "./tir/types/TirNativeType/native/data.js";
12
+ import { TirVoidT } from "./tir/types/TirNativeType/native/void.js";
13
+ import { TirSopOptT } from "./tir/types/TirNativeType/native/Optional/sop.js";
14
+ import { int_t, bool_t, bytes_t, string_t } from "./tir/program/stdScope/stdScope.js";
15
+ import { TirFuncExpr } from "./tir/expressions/TirFuncExpr.js";
16
+ import { TirBlockStmt } from "./tir/statements/TirBlockStmt.js";
17
+ import { TirIfStmt } from "./tir/statements/TirIfStmt.js";
18
+ import { TirReturnStmt } from "./tir/statements/TirReturnStmt.js";
19
+ import { TirAssertStmt } from "./tir/statements/TirAssertStmt.js";
20
+ import { TirForStmt } from "./tir/statements/TirForStmt.js";
21
+ import { TirForOfStmt } from "./tir/statements/TirForOfStmt.js";
22
+ import { TirWhileStmt } from "./tir/statements/TirWhileStmt.js";
23
+ import { TirMatchStmt } from "./tir/statements/TirMatchStmt.js";
24
+ import { TirAssignmentStmt } from "./tir/statements/TirAssignmentStmt.js";
25
+ import { TirTraceStmt } from "./tir/statements/TirTraceStmt.js";
26
+ import { TirSimpleVarDecl } from "./tir/statements/TirVarDecl/TirSimpleVarDecl.js";
27
+ import { TirNamedDeconstructVarDecl } from "./tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
28
+ import { TirSingleDeconstructVarDecl } from "./tir/statements/TirVarDecl/TirSingleDeconstructVarDecl.js";
29
+ import { TirArrayLikeDeconstr } from "./tir/statements/TirVarDecl/TirArrayLikeDeconstr.js";
30
+ import { TirCallExpr } from "./tir/expressions/TirCallExpr.js";
31
+ import { TirPropAccessExpr } from "./tir/expressions/TirPropAccessExpr.js";
32
+ import { TirVariableAccessExpr } from "./tir/expressions/TirVariableAccessExpr.js";
33
+ import { TirCaseExpr } from "./tir/expressions/TirCaseExpr.js";
34
+ import { TirElemAccessExpr } from "./tir/expressions/TirElemAccessExpr.js";
35
+ import { TirTernaryExpr } from "./tir/expressions/TirTernaryExpr.js";
36
+ import { TirParentesizedExpr } from "./tir/expressions/TirParentesizedExpr.js";
37
+ import { TirTypeConversionExpr } from "./tir/expressions/TirTypeConversionExpr.js";
38
+ import { TirLettedExpr } from "./tir/expressions/TirLettedExpr.js";
39
+ import { TirHoistedExpr } from "./tir/expressions/TirHoistedExpr.js";
40
+ import { TirFromDataExpr } from "./tir/expressions/TirFromDataExpr.js";
41
+ import { TirToDataExpr } from "./tir/expressions/TirToDataExpr.js";
42
+ import { TirAssertAndContinueExpr } from "./tir/expressions/TirAssertAndContinueExpr.js";
43
+ import { TirTraceIfFalseExpr } from "./tir/expressions/TirTraceIfFalseExpr.js";
44
+ import { TirTraceExpr } from "./tir/expressions/TirTraceExpr.js";
45
+ import { isTirBinaryExpr } from "./tir/expressions/binary/TirBinaryExpr.js";
46
+ import { isTirUnaryPrefixExpr } from "./tir/expressions/unary/TirUnaryPrefixExpr.js";
47
+ import { TirTypeParam } from "./tir/types/TirTypeParam.js";
48
+ import { isTirOptType } from "./tir/types/TirNativeType/native/Optional/isTirOptType.js";
49
+ export class SourceTypeMap {
50
+ program;
51
+ entries = [];
52
+ sorted = false;
53
+ constructor(program) {
54
+ this.program = program;
55
+ }
56
+ buildFromProgram() {
57
+ this.entries = [];
58
+ for (const [name, func] of this.program.functions) {
59
+ if (func instanceof TirFuncExpr) {
60
+ this.walkFuncExpr(func);
61
+ }
62
+ }
63
+ for (const [name, cnst] of this.program.constants) {
64
+ this.walkVarDecl(cnst);
65
+ }
66
+ this.sorted = false;
67
+ }
68
+ addEntry(start, end, type, name, kind) {
69
+ if (start >= 0 && end > start) {
70
+ this.entries.push({ start, end, type, name, kind });
71
+ }
72
+ }
73
+ ensureSorted() {
74
+ if (!this.sorted) {
75
+ // sort by start ascending, then by range size ascending (smallest/most specific first for ties)
76
+ this.entries.sort((a, b) => a.start - b.start || (a.end - a.start) - (b.end - b.start));
77
+ this.sorted = true;
78
+ }
79
+ }
80
+ typeAtOffset(offset) {
81
+ this.ensureSorted();
82
+ // find the most specific (smallest range) entry containing the offset
83
+ let best = undefined;
84
+ for (const entry of this.entries) {
85
+ if (entry.start > offset)
86
+ break; // sorted by start, so no more matches
87
+ if (offset >= entry.start && offset < entry.end) {
88
+ if (!best || (entry.end - entry.start) < (best.end - best.start)) {
89
+ best = entry;
90
+ }
91
+ }
92
+ }
93
+ return best;
94
+ }
95
+ allEntries() {
96
+ this.ensureSorted();
97
+ return this.entries;
98
+ }
99
+ membersOfType(type) {
100
+ // unwrap aliases
101
+ while (type instanceof TirAliasType) {
102
+ const aliasMembers = this.methodsFromMap(type.methodsNamesPtr);
103
+ if (aliasMembers.length > 0) {
104
+ // get fields from aliased + methods from alias
105
+ const innerMembers = this.membersOfType(type.aliased);
106
+ const fieldMembers = innerMembers.filter(m => m.kind === "field");
107
+ return [...fieldMembers, ...aliasMembers];
108
+ }
109
+ type = type.aliased;
110
+ }
111
+ if (type instanceof TirTypeParam)
112
+ return [];
113
+ if (isTirStructType(type))
114
+ return this.structMembers(type);
115
+ if (type instanceof TirVoidT)
116
+ return [];
117
+ if (type instanceof TirBoolT)
118
+ return [];
119
+ if (type instanceof TirIntT)
120
+ return [];
121
+ if (type instanceof TirBytesT)
122
+ return this.bytesMembers();
123
+ if (type instanceof TirStringT)
124
+ return this.stringMembers();
125
+ if (type instanceof TirDataT)
126
+ return [];
127
+ if (isTirOptType(type))
128
+ return [];
129
+ if (type instanceof TirFuncT)
130
+ return [];
131
+ if (type instanceof TirListT)
132
+ return this.listMembers(type.typeArg);
133
+ if (type instanceof TirLinearMapT)
134
+ return this.linearMapMembers(type.keyTypeArg, type.valTypeArg);
135
+ return [];
136
+ }
137
+ structMembers(type) {
138
+ const result = [];
139
+ // single-constructor structs expose fields directly
140
+ if (type.constructors.length === 1) {
141
+ const constr = type.constructors[0];
142
+ for (const field of constr.fields) {
143
+ result.push({ name: field.name, type: field.type, kind: "field" });
144
+ }
145
+ }
146
+ // methods
147
+ result.push(...this.methodsFromMap(type.methodNamesPtr));
148
+ return result;
149
+ }
150
+ methodsFromMap(methodsPtr) {
151
+ const result = [];
152
+ for (const [astName, tirName] of methodsPtr) {
153
+ const funcExpr = this.program.functions.get(tirName);
154
+ if (!funcExpr)
155
+ continue;
156
+ const fullSig = funcExpr.sig();
157
+ // method sig: drop first arg (self)
158
+ const methodSig = new TirFuncT(fullSig.argTypes.slice(1), fullSig.returnType);
159
+ result.push({ name: astName, type: methodSig, kind: "method" });
160
+ }
161
+ return result;
162
+ }
163
+ listMembers(elemType) {
164
+ const mapReturnT = new TirTypeParam("T");
165
+ return [
166
+ { name: "length", type: new TirFuncT([], int_t), kind: "method" },
167
+ { name: "isEmpty", type: new TirFuncT([], bool_t), kind: "method" },
168
+ { name: "show", type: new TirFuncT([], bytes_t), kind: "method" },
169
+ { name: "head", type: new TirFuncT([], elemType), kind: "method" },
170
+ { name: "tail", type: new TirFuncT([], new TirListT(elemType)), kind: "method" },
171
+ { name: "reverse", type: new TirFuncT([], new TirListT(elemType)), kind: "method" },
172
+ { name: "find", type: new TirFuncT([new TirFuncT([elemType], bool_t)], new TirSopOptT(elemType)), kind: "method" },
173
+ { name: "filter", type: new TirFuncT([new TirFuncT([elemType], bool_t)], new TirListT(elemType)), kind: "method" },
174
+ { name: "prepend", type: new TirFuncT([elemType], new TirListT(elemType)), kind: "method" },
175
+ { name: "map", type: new TirFuncT([new TirFuncT([elemType], mapReturnT)], new TirListT(mapReturnT)), kind: "method" },
176
+ { name: "every", type: new TirFuncT([new TirFuncT([elemType], bool_t)], bool_t), kind: "method" },
177
+ { name: "some", type: new TirFuncT([new TirFuncT([elemType], bool_t)], bool_t), kind: "method" },
178
+ { name: "includes", type: new TirFuncT([elemType], bool_t), kind: "method" },
179
+ ];
180
+ }
181
+ bytesMembers() {
182
+ return [
183
+ { name: "length", type: new TirFuncT([], int_t), kind: "method" },
184
+ { name: "subByteString", type: new TirFuncT([int_t, int_t], bytes_t), kind: "method" },
185
+ { name: "slice", type: new TirFuncT([int_t, int_t], bytes_t), kind: "method" },
186
+ { name: "show", type: new TirFuncT([], bytes_t), kind: "method" },
187
+ { name: "decodeUtf8", type: new TirFuncT([], string_t), kind: "method" },
188
+ { name: "prepend", type: new TirFuncT([int_t], bytes_t), kind: "method" },
189
+ ];
190
+ }
191
+ stringMembers() {
192
+ return [
193
+ ...this.bytesMembers(),
194
+ { name: "encodeUtf8", type: new TirFuncT([], bytes_t), kind: "method" },
195
+ ];
196
+ }
197
+ linearMapMembers(kT, vT) {
198
+ return [
199
+ { name: "lookup", type: new TirFuncT([kT], new TirSopOptT(vT)), kind: "method" },
200
+ ];
201
+ }
202
+ // --- TIR tree walkers ---
203
+ walkFuncExpr(func) {
204
+ // skip top-level entry for internal/compiler-generated functions
205
+ // (names starting with § or other internal prefixes)
206
+ // their range covers the whole contract body and pollutes typeAtOffset
207
+ if (!func.name || !func.name.startsWith("§")) {
208
+ this.addEntry(func.range.start, func.range.end, func.type, func.name);
209
+ }
210
+ for (const param of func.params) {
211
+ this.walkVarDecl(param);
212
+ }
213
+ this.walkStmt(func.body);
214
+ }
215
+ walkExpr(expr) {
216
+ if (!expr)
217
+ return;
218
+ // all expressions have range and type
219
+ try {
220
+ this.addEntry(expr.range.start, expr.range.end, expr.type);
221
+ }
222
+ catch { }
223
+ // recurse into sub-expressions
224
+ if (expr instanceof TirCallExpr) {
225
+ this.walkExpr(expr.func);
226
+ for (const arg of expr.args)
227
+ this.walkExpr(arg);
228
+ }
229
+ else if (expr instanceof TirPropAccessExpr) {
230
+ this.walkExpr(expr.object);
231
+ }
232
+ else if (expr instanceof TirVariableAccessExpr) {
233
+ // leaf — name is the variable name
234
+ this.addEntry(expr.range.start, expr.range.end, expr.type, expr.resolvedValue.variableInfos.name);
235
+ }
236
+ else if (expr instanceof TirFuncExpr) {
237
+ this.walkFuncExpr(expr);
238
+ }
239
+ else if (expr instanceof TirCaseExpr) {
240
+ this.walkExpr(expr.matchExpr);
241
+ for (const c of expr.cases) {
242
+ if (c.pattern)
243
+ this.walkVarDecl(c.pattern);
244
+ this.walkExpr(c.body);
245
+ }
246
+ if (expr.wildcardCase) {
247
+ this.walkExpr(expr.wildcardCase.body);
248
+ }
249
+ }
250
+ else if (expr instanceof TirElemAccessExpr) {
251
+ this.walkExpr(expr.arrLikeExpr);
252
+ this.walkExpr(expr.indexExpr);
253
+ }
254
+ else if (expr instanceof TirTernaryExpr) {
255
+ this.walkExpr(expr.condition);
256
+ this.walkExpr(expr.ifTrue);
257
+ this.walkExpr(expr.ifFalse);
258
+ }
259
+ else if (expr instanceof TirParentesizedExpr) {
260
+ this.walkExpr(expr.expr);
261
+ }
262
+ else if (expr instanceof TirTypeConversionExpr) {
263
+ this.walkExpr(expr.expr);
264
+ }
265
+ else if (expr instanceof TirLettedExpr) {
266
+ this.walkExpr(expr.expr);
267
+ }
268
+ else if (expr instanceof TirHoistedExpr) {
269
+ this.walkExpr(expr.expr);
270
+ }
271
+ else if (expr instanceof TirFromDataExpr) {
272
+ this.walkExpr(expr.expr);
273
+ }
274
+ else if (expr instanceof TirToDataExpr) {
275
+ this.walkExpr(expr.expr);
276
+ }
277
+ else if (expr instanceof TirAssertAndContinueExpr) {
278
+ this.walkExpr(expr.condition);
279
+ this.walkExpr(expr.continuation);
280
+ }
281
+ else if (expr instanceof TirTraceIfFalseExpr) {
282
+ this.walkExpr(expr.condition);
283
+ this.walkExpr(expr.traceMsg);
284
+ }
285
+ else if (expr instanceof TirTraceExpr) {
286
+ this.walkExpr(expr.traceMsg);
287
+ this.walkExpr(expr.continuation);
288
+ }
289
+ else if (isTirBinaryExpr(expr)) {
290
+ this.walkExpr(expr.left);
291
+ this.walkExpr(expr.right);
292
+ }
293
+ else if (isTirUnaryPrefixExpr(expr)) {
294
+ this.walkExpr(expr.operand);
295
+ }
296
+ // TirLitteralExpr, TirNativeFunc, TirFailExpr, TirInlineClosedIR — leaf nodes
297
+ }
298
+ walkStmt(stmt) {
299
+ if (!stmt)
300
+ return;
301
+ if (stmt instanceof TirBlockStmt) {
302
+ for (const s of stmt.stmts)
303
+ this.walkStmt(s);
304
+ }
305
+ else if (stmt instanceof TirIfStmt) {
306
+ this.walkExpr(stmt.condition);
307
+ this.walkStmt(stmt.thenBranch);
308
+ if (stmt.elseBranch)
309
+ this.walkStmt(stmt.elseBranch);
310
+ }
311
+ else if (stmt instanceof TirReturnStmt) {
312
+ this.walkExpr(stmt.value);
313
+ }
314
+ else if (stmt instanceof TirAssertStmt) {
315
+ this.walkExpr(stmt.condition);
316
+ if (stmt.elseExpr)
317
+ this.walkExpr(stmt.elseExpr);
318
+ }
319
+ else if (stmt instanceof TirForStmt) {
320
+ for (const v of stmt.init)
321
+ this.walkVarDecl(v);
322
+ if (stmt.condition)
323
+ this.walkExpr(stmt.condition);
324
+ if (stmt.update)
325
+ for (const s of stmt.update)
326
+ this.walkStmt(s);
327
+ this.walkStmt(stmt.body);
328
+ }
329
+ else if (stmt instanceof TirForOfStmt) {
330
+ this.walkVarDecl(stmt.elemDeclaration);
331
+ this.walkExpr(stmt.iterable);
332
+ this.walkStmt(stmt.body);
333
+ }
334
+ else if (stmt instanceof TirWhileStmt) {
335
+ this.walkExpr(stmt.condition);
336
+ this.walkStmt(stmt.body);
337
+ }
338
+ else if (stmt instanceof TirMatchStmt) {
339
+ this.walkExpr(stmt.matchExpr);
340
+ for (const c of stmt.cases) {
341
+ this.walkVarDecl(c.pattern);
342
+ this.walkStmt(c.body);
343
+ }
344
+ if (stmt.wildcardCase)
345
+ this.walkStmt(stmt.wildcardCase.body);
346
+ }
347
+ else if (stmt instanceof TirAssignmentStmt) {
348
+ this.walkExpr(stmt.varIdentifier);
349
+ this.walkExpr(stmt.assignedExpr);
350
+ }
351
+ else if (stmt instanceof TirTraceStmt) {
352
+ this.walkExpr(stmt.expr);
353
+ }
354
+ else if (stmt instanceof TirSimpleVarDecl) {
355
+ this.walkVarDecl(stmt);
356
+ }
357
+ else if (stmt instanceof TirNamedDeconstructVarDecl) {
358
+ this.walkVarDecl(stmt);
359
+ }
360
+ else if (stmt instanceof TirSingleDeconstructVarDecl) {
361
+ this.walkVarDecl(stmt);
362
+ }
363
+ else if (stmt instanceof TirArrayLikeDeconstr) {
364
+ this.walkVarDecl(stmt);
365
+ }
366
+ // TirBreakStmt, TirContinueStmt, TirFailStmt — no sub-expressions to walk
367
+ }
368
+ walkVarDecl(decl, isDeconstructField = false) {
369
+ if (decl instanceof TirSimpleVarDecl) {
370
+ // skip full-range entry for deconstruct fields — their parent's fieldLabelRanges provides correct tight-range entries
371
+ if (!isDeconstructField) {
372
+ // internal-named params (§-prefixed) use sourceName if available
373
+ const displayName = decl.sourceName ?? (isInternalName(decl.name) ? undefined : decl.name);
374
+ if (displayName !== undefined) {
375
+ this.addEntry(decl.range.start, decl.range.end, decl.type, displayName);
376
+ }
377
+ }
378
+ // add entry for explicit type annotation as a type reference
379
+ if (decl.typeAnnotationRange) {
380
+ this.addEntry(decl.typeAnnotationRange.start, decl.typeAnnotationRange.end, decl.type, undefined, "type-reference");
381
+ }
382
+ if (decl.initExpr)
383
+ this.walkExpr(decl.initExpr);
384
+ }
385
+ else if (decl instanceof TirNamedDeconstructVarDecl) {
386
+ // add entry for the constructor name as a type reference (for LSP coloring)
387
+ if (decl.constrNameRange) {
388
+ this.addEntry(decl.constrNameRange.start, decl.constrNameRange.end, decl.type, decl.constrName, "type-reference");
389
+ }
390
+ // add entry for explicit type annotation as a type reference
391
+ if (decl.typeAnnotationRange) {
392
+ this.addEntry(decl.typeAnnotationRange.start, decl.typeAnnotationRange.end, decl.type, undefined, "type-reference");
393
+ }
394
+ // add entries for field labels (hovering field name shows the field's type from the constructor definition)
395
+ if (decl.fieldLabelRanges) {
396
+ for (const [fieldName, labelInfo] of decl.fieldLabelRanges) {
397
+ this.addEntry(labelInfo.range.start, labelInfo.range.end, labelInfo.type, fieldName);
398
+ }
399
+ }
400
+ if (decl.initExpr)
401
+ this.walkExpr(decl.initExpr);
402
+ for (const field of decl.fields.values()) {
403
+ this.walkVarDecl(field, true);
404
+ }
405
+ }
406
+ else if (decl instanceof TirSingleDeconstructVarDecl) {
407
+ // add entry for explicit type annotation as a type reference
408
+ if (decl.typeAnnotationRange) {
409
+ this.addEntry(decl.typeAnnotationRange.start, decl.typeAnnotationRange.end, decl.type, undefined, "type-reference");
410
+ }
411
+ // add entries for field labels (hovering field name shows the field's type from the constructor definition)
412
+ if (decl.fieldLabelRanges) {
413
+ for (const [fieldName, labelInfo] of decl.fieldLabelRanges) {
414
+ this.addEntry(labelInfo.range.start, labelInfo.range.end, labelInfo.type, fieldName);
415
+ }
416
+ }
417
+ if (decl.initExpr)
418
+ this.walkExpr(decl.initExpr);
419
+ for (const field of decl.fields.values()) {
420
+ this.walkVarDecl(field, true);
421
+ }
422
+ }
423
+ else if (decl instanceof TirArrayLikeDeconstr) {
424
+ this.addEntry(decl.range.start, decl.range.end, decl.type);
425
+ if (decl.initExpr)
426
+ this.walkExpr(decl.initExpr);
427
+ for (const elem of decl.elements) {
428
+ this.walkVarDecl(elem);
429
+ }
430
+ }
431
+ }
432
+ }