| import {from, trim, charat, strlen, substr, append, assign} from './Utility.js' |
| |
| export var line = 1 |
| export var column = 1 |
| export var length = 0 |
| export var position = 0 |
| export var character = 0 |
| export var characters = '' |
| |
| /** |
| * @param {string} value |
| * @param {object | null} root |
| * @param {object | null} parent |
| * @param {string} type |
| * @param {string[] | string} props |
| * @param {object[] | string} children |
| * @param {number} length |
| */ |
| export function node (value, root, parent, type, props, children, length) { |
| return {value: value, root: root, parent: parent, type: type, props: props, children: children, line: line, column: column, length: length, return: ''} |
| } |
| |
| /** |
| * @param {object} root |
| * @param {object} props |
| * @return {object} |
| */ |
| export function copy (root, props) { |
| return assign(node('', null, null, '', null, null, 0), root, {length: -root.length}, props) |
| } |
| |
| /** |
| * @return {number} |
| */ |
| export function char () { |
| return character |
| } |
| |
| /** |
| * @return {number} |
| */ |
| export function prev () { |
| character = position > 0 ? charat(characters, --position) : 0 |
| |
| if (column--, character === 10) |
| column = 1, line-- |
| |
| return character |
| } |
| |
| /** |
| * @return {number} |
| */ |
| export function next () { |
| character = position < length ? charat(characters, position++) : 0 |
| |
| if (column++, character === 10) |
| column = 1, line++ |
| |
| return character |
| } |
| |
| /** |
| * @return {number} |
| */ |
| export function peek () { |
| return charat(characters, position) |
| } |
| |
| /** |
| * @return {number} |
| */ |
| export function caret () { |
| return position |
| } |
| |
| /** |
| * @param {number} begin |
| * @param {number} end |
| * @return {string} |
| */ |
| export function slice (begin, end) { |
| return substr(characters, begin, end) |
| } |
| |
| /** |
| * @param {number} type |
| * @return {number} |
| */ |
| export function token (type) { |
| switch (type) { |
| // \0 \t \n \r \s whitespace token |
| case 0: case 9: case 10: case 13: case 32: |
| return 5 |
| // ! + , / > @ ~ isolate token |
| case 33: case 43: case 44: case 47: case 62: case 64: case 126: |
| // ; { } breakpoint token |
| case 59: case 123: case 125: |
| return 4 |
| // : accompanied token |
| case 58: |
| return 3 |
| // " ' ( [ opening delimit token |
| case 34: case 39: case 40: case 91: |
| return 2 |
| // ) ] closing delimit token |
| case 41: case 93: |
| return 1 |
| } |
| |
| return 0 |
| } |
| |
| /** |
| * @param {string} value |
| * @return {any[]} |
| */ |
| export function alloc (value) { |
| return line = column = 1, length = strlen(characters = value), position = 0, [] |
| } |
| |
| /** |
| * @param {any} value |
| * @return {any} |
| */ |
| export function dealloc (value) { |
| return characters = '', value |
| } |
| |
| /** |
| * @param {number} type |
| * @return {string} |
| */ |
| export function delimit (type) { |
| return trim(slice(position - 1, delimiter(type === 91 ? type + 2 : type === 40 ? type + 1 : type))) |
| } |
| |
| /** |
| * @param {string} value |
| * @return {string[]} |
| */ |
| export function tokenize (value) { |
| return dealloc(tokenizer(alloc(value))) |
| } |
| |
| /** |
| * @param {number} type |
| * @return {string} |
| */ |
| export function whitespace (type) { |
| while (character = peek()) |
| if (character < 33) |
| next() |
| else |
| break |
| |
| return token(type) > 2 || token(character) > 3 ? '' : ' ' |
| } |
| |
| /** |
| * @param {string[]} children |
| * @return {string[]} |
| */ |
| export function tokenizer (children) { |
| while (next()) |
| switch (token(character)) { |
| case 0: append(identifier(position - 1), children) |
| break |
| case 2: append(delimit(character), children) |
| break |
| default: append(from(character), children) |
| } |
| |
| return children |
| } |
| |
| /** |
| * @param {number} index |
| * @param {number} count |
| * @return {string} |
| */ |
| export function escaping (index, count) { |
| while (--count && next()) |
| // not 0-9 A-F a-f |
| if (character < 48 || character > 102 || (character > 57 && character < 65) || (character > 70 && character < 97)) |
| break |
| |
| return slice(index, caret() + (count < 6 && peek() == 32 && next() == 32)) |
| } |
| |
| /** |
| * @param {number} type |
| * @return {number} |
| */ |
| export function delimiter (type) { |
| while (next()) |
| switch (character) { |
| // ] ) " ' |
| case type: |
| return position |
| // " ' |
| case 34: case 39: |
| if (type !== 34 && type !== 39) |
| delimiter(character) |
| break |
| // ( |
| case 40: |
| if (type === 41) |
| delimiter(type) |
| break |
| // \ |
| case 92: |
| next() |
| break |
| } |
| |
| return position |
| } |
| |
| /** |
| * @param {number} type |
| * @param {number} index |
| * @return {number} |
| */ |
| export function commenter (type, index) { |
| while (next()) |
| // // |
| if (type + character === 47 + 10) |
| break |
| // /* |
| else if (type + character === 42 + 42 && peek() === 47) |
| break |
| |
| return '/*' + slice(index, position - 1) + '*' + from(type === 47 ? type : next()) |
| } |
| |
| /** |
| * @param {number} index |
| * @return {string} |
| */ |
| export function identifier (index) { |
| while (!token(peek())) |
| next() |
| |
| return slice(index, position) |
| } |