@puruslang/prettier-plugin-purus 0.7.1 → 0.8.1

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +74 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@puruslang/prettier-plugin-purus",
3
- "version": "0.7.1",
3
+ "version": "0.8.1",
4
4
  "description": "Prettier plugin for the Purus language",
5
5
  "license": "Apache-2.0",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -4,25 +4,28 @@ const KEYWORDS = new Set([
4
4
  "const", "let", "var", "be",
5
5
  "fn", "async", "return", "to", "gives",
6
6
  "if", "elif", "else", "unless", "then",
7
- "while", "until", "for", "in", "range",
8
- "match", "when", "witch", "case",
7
+ "while", "until", "do", "for", "in", "range",
8
+ "match", "when", "switch", "case",
9
9
  "try", "catch", "finally", "throw",
10
10
  "import", "from", "export", "default", "require", "use", "namespace", "public", "all", "with",
11
- "add", "sub", "mul", "div", "mod", "neg", "pow",
11
+ "add", "sub", "mul", "div", "fdiv", "mod", "neg", "pow",
12
12
  "eq", "neq", "lt", "gt", "le", "ge",
13
13
  "and", "or", "not", "pipe", "coal",
14
- "is", "as", "of", "typeof", "instanceof", "type",
15
- "new", "delete", "this", "await",
16
- "class", "extends", "super", "static", "private", "get", "set",
17
- "true", "false", "null", "nil", "undefined", "nan",
14
+ "band", "bor", "bxor", "bnot", "shl", "shr", "ushr",
15
+ "as", "of", "typeof", "instanceof", "type",
16
+ "new", "delete", "this", "await", "yield", "void",
17
+ "class", "extends", "super", "static", "private", "protected", "get", "set",
18
+ "true", "false", "null", "nil", "undefined", "nan", "infinity",
18
19
  "break", "continue",
19
20
  "list", "object",
21
+ "function",
20
22
  ]);
21
23
 
22
24
  const BLOCK_STARTERS = new Set([
23
25
  "fn", "if", "elif", "else", "unless",
24
- "while", "until", "for",
25
- "match", "when", "witch", "case",
26
+ "while", "until", "do", "for",
27
+ "match", "when", "switch", "case",
28
+ "try", "catch", "finally", "class",
26
29
  ]);
27
30
 
28
31
  function tokenize(source) {
@@ -136,13 +139,25 @@ function tokenize(source) {
136
139
  continue;
137
140
  }
138
141
 
139
- // Number
142
+ // Number (decimal, 0b binary, 0x hex, BigInt n-suffix)
140
143
  if (/[0-9]/.test(source[i])) {
141
144
  let start = i;
142
- while (i < len && /[0-9]/.test(source[i])) i++;
143
- if (i < len && source[i] === "." && i + 1 < len && /[0-9]/.test(source[i + 1])) {
144
- i++;
145
+ if (source[i] === "0" && i + 1 < len && (source[i + 1] === "b" || source[i + 1] === "B")) {
146
+ i += 2;
147
+ while (i < len && /[01]/.test(source[i])) i++;
148
+ } else if (source[i] === "0" && i + 1 < len && (source[i + 1] === "x" || source[i + 1] === "X")) {
149
+ i += 2;
150
+ while (i < len && /[0-9a-fA-F]/.test(source[i])) i++;
151
+ } else {
145
152
  while (i < len && /[0-9]/.test(source[i])) i++;
153
+ if (i < len && source[i] === "." && i + 1 < len && /[0-9]/.test(source[i + 1])) {
154
+ i++;
155
+ while (i < len && /[0-9]/.test(source[i])) i++;
156
+ }
157
+ }
158
+ // BigInt suffix: n
159
+ if (i < len && source[i] === "n" && (i + 1 >= len || !/[a-zA-Z0-9_]/.test(source[i + 1]))) {
160
+ i++;
146
161
  }
147
162
  tokens.push({ type: "number", value: source.slice(start, i) });
148
163
  continue;
@@ -213,6 +228,32 @@ function isEmptyLine(lineTokens) {
213
228
  return lineTokens.every(t => t.type === "whitespace");
214
229
  }
215
230
 
231
+ /**
232
+ * Returns "postfix", "prefix", or null for the backslash token at content[ti].
233
+ * Postfix: (ident | ] | number) \ (add|sub keyword) → x\add, x\sub
234
+ * Prefix: (add|sub keyword) \ ident → add\x, sub\x
235
+ */
236
+ function isIncrDecrSlash(content, ti) {
237
+ if (content[ti].value !== "\\") return null;
238
+ let ni = ti + 1;
239
+ while (ni < content.length && content[ni].type === "whitespace") ni++;
240
+ let pi = ti - 1;
241
+ while (pi >= 0 && content[pi].type === "whitespace") pi--;
242
+ const nextTok = ni < content.length ? content[ni] : null;
243
+ const prevTok = pi >= 0 ? content[pi] : null;
244
+ if (nextTok && nextTok.type === "keyword" && (nextTok.value === "add" || nextTok.value === "sub")) {
245
+ if (prevTok && (prevTok.type === "ident" || prevTok.value === "]" || prevTok.type === "number")) {
246
+ return "postfix";
247
+ }
248
+ }
249
+ if (prevTok && prevTok.type === "keyword" && (prevTok.value === "add" || prevTok.value === "sub")) {
250
+ if (nextTok && nextTok.type === "ident") {
251
+ return "prefix";
252
+ }
253
+ }
254
+ return null;
255
+ }
256
+
216
257
  function formatPurus(source, options = {}) {
217
258
  const indent = options.tabWidth || 2;
218
259
  const useTabs = options.useTabs || false;
@@ -258,22 +299,37 @@ function formatPurus(source, options = {}) {
258
299
  // Normalize to single space between tokens, but not before [ or after [, or before ]
259
300
  const next = content[ti + 1];
260
301
  const prevChar = lineStr.length > 0 ? lineStr[lineStr.length - 1] : "";
261
- if (lineStr.length > 0 && next && next.value !== "]" && next.value !== "[" && prevChar !== "[") {
302
+ // Suppress space before an incr/decr backslash
303
+ const nextIsIncrDecrSlash = next && next.value === "\\" && isIncrDecrSlash(content, ti + 1) !== null;
304
+ // Suppress space after an incr/decr backslash
305
+ let prevIsIncrDecrSlash = false;
306
+ { let pi = ti - 1; while (pi >= 0 && content[pi].type === "whitespace") pi--;
307
+ prevIsIncrDecrSlash = pi >= 0 && content[pi].value === "\\" && isIncrDecrSlash(content, pi) !== null; }
308
+ if (lineStr.length > 0 && next && next.value !== "]" && next.value !== "[" && prevChar !== "[" && !nextIsIncrDecrSlash && !prevIsIncrDecrSlash) {
262
309
  lineStr += " ";
263
310
  }
264
311
  } else {
265
312
  if (ti > 0 && content[ti - 1].type !== "whitespace" && lineStr.length > 0) {
266
313
  // Adjacent non-whitespace tokens - check if space needed
267
314
  const prev = lineStr[lineStr.length - 1];
315
+ let suppressSpace = false;
268
316
  if (tok.value === "." || prev === ".") {
269
- // No space around dots
317
+ suppressSpace = true; // No space around dots
270
318
  } else if (tok.value === "," || tok.value === ";") {
271
- // No space before comma/semicolon
319
+ suppressSpace = true; // No space before comma/semicolon
272
320
  } else if (tok.value === "[" || tok.value === "]" || prev === "[") {
273
- // No space around brackets (function call syntax)
321
+ suppressSpace = true; // No space around brackets
322
+ } else if (tok.value === "\\" && isIncrDecrSlash(content, ti) !== null) {
323
+ suppressSpace = true; // No space before incr/decr backslash
274
324
  } else {
275
- lineStr += " ";
325
+ // No space after incr/decr backslash
326
+ let pi = ti - 1;
327
+ while (pi >= 0 && content[pi].type === "whitespace") pi--;
328
+ if (pi >= 0 && content[pi].value === "\\" && isIncrDecrSlash(content, pi) !== null) {
329
+ suppressSpace = true;
330
+ }
276
331
  }
332
+ if (!suppressSpace) lineStr += " ";
277
333
  }
278
334
  lineStr += tok.value;
279
335
  }