```ts
export function scanSource(line: string): [string, string][] {
  const tokens: [string, string][] = [];
  let i = 0;

  while (i < line.length) {
    const char = line[i];

    if (char === ' ' || char === '\t') {
      i++;
      continue;
    }

    if (/\d/.test(char)) {
      let numText = '';
      do {
        numText += line[i];
        i++;
      } while (i < line.length && /\d/.test(line[i]));
      tokens.push(['num', numText]);
      continue;
    }

    if (/[a-zA-Z_]/.test(char)) {
      let idText = '';
      do {
        idText += line[i];
        i++;
      } while (i < line.length && /[a-zA-Z0-9_]/.test(line[i]));
      tokens.push(['id', idText]);
      continue;
    }

    if (char === '=' || char === '<' || char === '>' || char === '+' || char === '-' || char === '*' || char === '/' || char === '(' || char === ')') {
      tokens.push(['op', char]);
      i++;
      continue;
    }

    if (i + 1 < line.length && ((char === '!' && line[i + 1] === '=') || (char === '<' && line[i + 1] === '=') || (char === '>' && line[i + 1] === '=') || (char === '&' && line[i + 1] === '&') || (char === '|' && line[i + 1] === '|'))) {
      tokens.push(['op', char + line[i + 1]]);
      i += 2;
      continue;
    }

    throw new Error(`Invalid character: ${char}`);
  }

  return tokens;
}
```