gofront 0.0.3 → 0.0.5

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.
@@ -47,7 +47,13 @@ export const BOOL = { kind: "basic", name: "bool" };
47
47
  export const ANY = { kind: "basic", name: "any" };
48
48
  export const VOID = { kind: "basic", name: "void" };
49
49
  export const NIL = { kind: "basic", name: "nil" };
50
- export const ERROR = { kind: "basic", name: "error" };
50
+ export const ERROR = {
51
+ kind: "interface",
52
+ name: "error",
53
+ methods: new Map([
54
+ ["Error", { kind: "func", params: [], returns: [STRING], async: false }],
55
+ ]),
56
+ };
51
57
 
52
58
  // ── Untyped constant types (Go spec §Constants) ─────────────
53
59
  // Untyped constants coerce to any compatible typed context.
@@ -56,6 +62,11 @@ export const UNTYPED_FLOAT = { kind: "untyped", base: "float64" };
56
62
  export const UNTYPED_STRING = { kind: "untyped", base: "string" };
57
63
  export const UNTYPED_BOOL = { kind: "untyped", base: "bool" };
58
64
 
65
+ // ── Complex types ────────────────────────────────────────────
66
+ export const COMPLEX128 = { kind: "basic", name: "complex128" };
67
+ export const COMPLEX64 = { kind: "basic", name: "complex64" };
68
+ export const UNTYPED_COMPLEX = { kind: "untyped", base: "complex128" };
69
+
59
70
  export const BASIC_TYPES = {
60
71
  int: INT,
61
72
  float64: FLOAT64,
@@ -64,7 +75,6 @@ export const BASIC_TYPES = {
64
75
  any: ANY,
65
76
  byte: INT,
66
77
  rune: INT,
67
- error: ERROR,
68
78
  // Sized integer / float aliases — all map to int or float64 at runtime
69
79
  uint: INT,
70
80
  int8: INT,
@@ -77,19 +87,51 @@ export const BASIC_TYPES = {
77
87
  uint64: INT,
78
88
  uintptr: INT,
79
89
  float32: FLOAT64,
90
+ complex64: COMPLEX64,
91
+ complex128: COMPLEX128,
80
92
  };
81
93
 
94
+ export const COMPARABLE = { kind: "basic", name: "comparable" };
95
+
96
+ export function isTypeParam(t) {
97
+ return t?.kind === "typeParam";
98
+ }
99
+
100
+ export function isGeneric(t) {
101
+ return t?.kind === "generic";
102
+ }
103
+
82
104
  export function isNumeric(t) {
83
- if (t?.kind === "untyped") return t.base === "int" || t.base === "float64";
84
- return t?.kind === "basic" && (t.name === "int" || t.name === "float64");
105
+ if (!t) return false;
106
+ if (t.kind === "untyped") return t.base === "int" || t.base === "float64";
107
+ if (t.kind === "basic") return t.name === "int" || t.name === "float64";
108
+ if (t.kind === "named") return isNumeric(t.underlying);
109
+ return false;
110
+ }
111
+ export function isComplex(t) {
112
+ if (!t) return false;
113
+ if (t.kind === "basic" && (t.name === "complex128" || t.name === "complex64"))
114
+ return true;
115
+ if (t.kind === "untyped" && t.base === "complex128") return true;
116
+ if (t.kind === "named") return isComplex(t.underlying);
117
+ return false;
118
+ }
119
+ export function isComplexOrNumeric(t) {
120
+ return isNumeric(t) || isComplex(t);
85
121
  }
86
122
  export function isString(t) {
87
- if (t?.kind === "untyped") return t.base === "string";
88
- return t?.kind === "basic" && t.name === "string";
123
+ if (!t) return false;
124
+ if (t.kind === "untyped") return t.base === "string";
125
+ if (t.kind === "basic") return t.name === "string";
126
+ if (t.kind === "named") return isString(t.underlying);
127
+ return false;
89
128
  }
90
129
  export function isBool(t) {
91
- if (t?.kind === "untyped") return t.base === "bool";
92
- return t?.kind === "basic" && t.name === "bool";
130
+ if (!t) return false;
131
+ if (t.kind === "untyped") return t.base === "bool";
132
+ if (t.kind === "basic") return t.name === "bool";
133
+ if (t.kind === "named") return isBool(t.underlying);
134
+ return false;
93
135
  }
94
136
  export function isAny(t) {
95
137
  return t?.kind === "basic" && t.name === "any";
@@ -101,7 +143,23 @@ export function isVoid(t) {
101
143
  return t?.kind === "basic" && t.name === "void";
102
144
  }
103
145
  export function isError(t) {
104
- return t?.kind === "basic" && t.name === "error";
146
+ if (!t) return false;
147
+ if (t === ERROR) return true;
148
+ if (t.kind === "interface" && t.name === "error") return true;
149
+ if (t.kind === "named" && isError(t.underlying)) return true;
150
+ return false;
151
+ }
152
+ export function isPointer(t) {
153
+ if (!t) return false;
154
+ if (t.kind === "pointer") return true;
155
+ if (t.kind === "named") return t.underlying?.kind === "pointer";
156
+ return false;
157
+ }
158
+ export function isArray(t) {
159
+ if (!t) return false;
160
+ if (t.kind === "array") return true;
161
+ if (t.kind === "named") return t.underlying?.kind === "array";
162
+ return false;
105
163
  }
106
164
  export function isUntyped(t) {
107
165
  return t?.kind === "untyped";
@@ -119,29 +177,13 @@ export function defaultType(t) {
119
177
  return STRING;
120
178
  case "bool":
121
179
  return BOOL;
180
+ case "complex128":
181
+ return COMPLEX128;
122
182
  default:
123
183
  return ANY;
124
184
  }
125
185
  }
126
186
 
127
- /** Convert a concrete basic type to its untyped equivalent (for const inference). */
128
- export function toUntyped(t) {
129
- if (t?.kind === "untyped") return t;
130
- if (t?.kind === "basic") {
131
- switch (t.name) {
132
- case "int":
133
- return UNTYPED_INT;
134
- case "float64":
135
- return UNTYPED_FLOAT;
136
- case "string":
137
- return UNTYPED_STRING;
138
- case "bool":
139
- return UNTYPED_BOOL;
140
- }
141
- }
142
- return t;
143
- }
144
-
145
187
  export function typeStr(t) {
146
188
  if (!t) return "void";
147
189
  if (t.kind === "basic" && t.alias) return t.alias;
@@ -153,7 +195,7 @@ export function typeStr(t) {
153
195
  case "slice":
154
196
  return `[]${typeStr(t.elem)}`;
155
197
  case "array":
156
- return `[${t.size}]${typeStr(t.elem)}`;
198
+ return `[${t.size ?? "..."}]${typeStr(t.elem)}`;
157
199
  case "map":
158
200
  return `map[${typeStr(t.key)}]${typeStr(t.value)}`;
159
201
  case "struct":
@@ -170,11 +212,37 @@ export function typeStr(t) {
170
212
  return t.name;
171
213
  case "pointer":
172
214
  return `*${typeStr(t.base)}`;
215
+ case "typeParam":
216
+ return t.name;
217
+ case "generic":
218
+ return t.name || `generic(${typeStr(t.underlying)})`;
173
219
  default:
174
220
  return "?";
175
221
  }
176
222
  }
177
223
 
224
+ // ── Iterator function detection (Go 1.23 range-over-func) ───
225
+
226
+ /**
227
+ * Returns null if t is not an iterator function.
228
+ * Returns { yieldParams: Type[] } if it is, where yieldParams are the
229
+ * types the range variables will be bound to (0, 1, or 2 elements).
230
+ *
231
+ * An iterator is func(yield func(...) bool) — single param that is a
232
+ * func returning bool with 0-2 params.
233
+ */
234
+ export function iteratorYieldParams(t) {
235
+ const fn = t?.kind === "named" ? t.underlying : t;
236
+ if (fn?.kind !== "func") return null;
237
+ if (fn.params.length !== 1) return null;
238
+ const yieldFn =
239
+ fn.params[0]?.kind === "named" ? fn.params[0].underlying : fn.params[0];
240
+ if (yieldFn?.kind !== "func") return null;
241
+ if (yieldFn.returns.length !== 1 || !isBool(yieldFn.returns[0])) return null;
242
+ if (yieldFn.params.length > 2) return null;
243
+ return { yieldParams: yieldFn.params };
244
+ }
245
+
178
246
  // ── Scope / environment ──────────────────────────────────────
179
247
 
180
248
  export class Scope {