import { ExternalTokenizer, ContextTracker } from '@lezer/lr';
import {
  insertSemi,
  noSemi,
  incdec,
  incdecPrefix,
  spaces,
  newline,
  BlockComment,
  LineComment,
} from './parser.terms.js';

const space = [
  9, 10, 11, 12, 13, 32, 133, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197,
  8198, 8199, 8200, 8201, 8202, 8232, 8233, 8239, 8287, 12288,
];

const braceR = 125,
  semicolon = 59,
  slash = 47,
  star = 42,
  plus = 43,
  minus = 45;

export const trackNewline = new ContextTracker({
  start: false,
  shift(context, term) {
    return term === LineComment || term === BlockComment || term === spaces
      ? context
      : term === newline;
  },
  strict: false,
});

export const insertSemicolon = new ExternalTokenizer(
  (input, stack) => {
    let { next } = input;
    if (next === braceR || next === -1 || stack.context)
      input.acceptToken(insertSemi);
  },
  { contextual: true, fallback: true }
);

export const noSemicolon = new ExternalTokenizer(
  (input, stack) => {
    let { next } = input,
      after;
    if (space.indexOf(next) > -1) return;
    if (next === slash && ((after = input.peek(1)) === slash || after === star))
      return;
    if (next !== braceR && next !== semicolon && next !== -1 && !stack.context)
      input.acceptToken(noSemi);
  },
  { contextual: true }
);

export const incdecToken = new ExternalTokenizer(
  (input, stack) => {
    let { next } = input;
    if (next === plus || next === minus) {
      input.advance();
      if (next === input.next) {
        input.advance();
        let mayPostfix = !stack.context && stack.canShift(incdec);
        input.acceptToken(mayPostfix ? incdec : incdecPrefix);
      }
    }
  },
  { contextual: true }
);
