yaml-language-server-parser
Version:
This is a maintained fork of YAML-AST-PARSER specifically for the YAML Language server.
191 lines (151 loc) • 4.2 kB
text/typescript
'use strict';
import common = require('../common');
import { Type } from '../type';
import ast = require('../yamlAST');
function isHexCode(c) {
return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) ||
((0x41/* A */ <= c) && (c <= 0x46/* F */)) ||
((0x61/* a */ <= c) && (c <= 0x66/* f */));
}
function isOctCode(c) {
return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */));
}
function isDecCode(c) {
return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */));
}
function resolveYamlInteger(nodeOrString: ast.YAMLNode | string) {
const integerValue = ast.isYAMLNode(nodeOrString) ? (nodeOrString as ast.YAMLNode).value : nodeOrString;
if (null === integerValue) {
return false;
}
var max = integerValue.length,
index = 0,
hasDigits = false,
ch;
if (!max) { return false; }
ch = integerValue[index];
// sign
if (ch === '-' || ch === '+') {
ch = integerValue[++index];
}
if (ch === '0') {
// 0
if (index + 1 === max) { return true; }
ch = integerValue[++index];
// base 2, base 8, base 16
if (ch === 'b') {
// base 2
index++;
for (; index < max; index++) {
ch = integerValue[index];
if (ch === '_') { continue; }
if (ch !== '0' && ch !== '1') {
return false;
}
hasDigits = true;
}
return hasDigits;
}
if (ch === 'x') {
// base 16
index++;
for (; index < max; index++) {
ch = integerValue[index];
if (ch === '_') { continue; }
if (!isHexCode(integerValue.charCodeAt(index))) {
return false;
}
hasDigits = true;
}
return hasDigits;
}
// base 8
for (; index < max; index++) {
ch = integerValue[index];
if (ch === '_') { continue; }
if (!isOctCode(integerValue.charCodeAt(index))) {
return false;
}
hasDigits = true;
}
return hasDigits;
}
// base 10 (except 0) or base 60
for (; index < max; index++) {
ch = integerValue[index];
if (ch === '_') { continue; }
if (ch === ':') { break; }
if (!isDecCode(integerValue.charCodeAt(index))) {
return false;
}
hasDigits = true;
}
if (!hasDigits) { return false; }
// if !base60 - done;
if (ch !== ':') { return true; }
// base60 almost not used, no needs to optimize
return /^(:[0-5]?[0-9])+$/.test(integerValue.slice(index));
}
function constructYamlInteger(nodeOrString: ast.YAMLNode | string) {
if (ast.isYAMLNode(nodeOrString)) {
return nodeOrString;
}
var value = nodeOrString as any, sign = 1, ch, base, digits = [];
if (value.indexOf('_') !== -1) {
value = value.replace(/_/g, '');
}
ch = value[0];
if (ch === '-' || ch === '+') {
if (ch === '-') { sign = -1; }
value = value.slice(1);
ch = value[0];
}
if ('0' === value) {
return 0;
}
if (ch === '0') {
if (value[1] === 'b') {
return sign * parseInt(value.slice(2), 2);
}
if (value[1] === 'x') {
return sign * parseInt(value, 16);
}
return sign * parseInt(value, 8);
}
if (value.indexOf(':') !== -1) {
value.split(':').forEach(function (v) {
digits.unshift(parseInt(v, 10));
});
value = 0;
base = 1;
digits.forEach(function (d) {
value += (d * base);
base *= 60;
});
return sign * value;
}
return sign * parseInt(value, 10);
}
function isInteger(object) {
return ('[object Number]' === Object.prototype.toString.call(object)) &&
(0 === object % 1 && !common.isNegativeZero(object));
}
export = new Type('tag:yaml.org,2002:int', {
kind: 'scalar',
resolve: resolveYamlInteger,
construct: constructYamlInteger,
predicate: isInteger,
represent: {
binary: function (object) { return '0b' + object.toString(2); },
octal: function (object) { return '0' + object.toString(8); },
decimal: function (object) { return object.toString(10); },
hexadecimal: function (object) { return '0x' + object.toString(16).toUpperCase(); }
},
defaultStyle: 'decimal',
styleAliases: {
binary: [2, 'bin'],
octal: [8, 'oct'],
decimal: [10, 'dec'],
hexadecimal: [16, 'hex']
}
});