// ==UserScript==
// @name Statement Parser
// @namespace http://tampermonkey.net/
// @version 1.0.7
// @description 【使用前先看介绍/有问题可反馈】声明解析器 (Statement Parser):通过语言,类型,变量名,以及赋值,直接生成可被解析的声明语句。
// @author cc
// @include *
// @grant none
// ==/UserScript==
(function() {
const __VERSION__ = '1.0.7';
class StatementParser {
static get __VERSION__() {
return __VERSION__;
}
static #conf = {
'Java': {
lang: 'Java',
baseType: ['boolean', 'byte', 'char', 'short', 'int', 'long', 'long', 'float', 'double', 'String'],
extendType: [/^ListNode$/],
useArray: true,
arrayBrackets: '{}',
squareBracketsPostPosition: false,
usePointer: false,
useGenerics: true,
useNewForArray: true,
useNewForObject: true,
accessProperty: '.',
nullValue: 'null',
classStructSlice: [2, -1],
commentChar: '*',
singleLineCommentStartsWith: '//',
endsWithSemicolon: true,
typePostPosition: false,
useTypeDeclare: true,
useKeywordDeclare: false,
declareKeyword: '',
ignoreThisArg: false,
useSplit: true,
declareTemplate: /public\s+[\w<>\[\]]+\s+\w+\(\s*(.+?)\s*\)/,
template: /^(.+)\s+(\w+)$/,
},
'C++': {
lang: 'C++',
baseType: ['void', 'bool', 'char', 'short', 'int', 'long', 'float', 'double', 'string'],
extendType: [/^ListNode\s*\*$/, /^vector<(.+)>$/],
useArray: false,
arrayBrackets: '{}',
squareBracketsPostPosition: true,
usePointer: true,
useGenerics: true,
useNewForArray: true,
useNewForObject: true,
accessProperty: '->',
nullValue: 'NULL',
classStructSlice: [2, -1],
commentChar: '*',
singleLineCommentStartsWith: '//',
endsWithSemicolon: true,
typePostPosition: false,
useTypeDeclare: true,
useKeywordDeclare: false,
declareKeyword: '',
ignoreThisArg: false,
useSplit: true,
declareTemplate: /public:\s+[\w<>*]+\s*[&*]?\s*\w+\(\s*(.+?)\s*\)/,
template: /^(.+?\s*?\*?)&?\s*(\w+)$/,
},
'Python3': {
lang: 'Python3',
baseType: ['bool', 'int', 'float', 'str'],
extendType: [/^List\[(.+)]$/, /^ListNode$/],
useArray: false,
arrayBrackets: '[]',
squareBracketsPostPosition: true,
usePointer: false,
useGenerics: true,
useNewForArray: false,
useNewForObject: false,
accessProperty: '.',
nullValue: 'None',
classStructSlice: [1, 0],
commentChar: '#',
singleLineCommentStartsWith: '#',
endsWithSemicolon: false,
typePostPosition: true,
useTypeDeclare: false,
useKeywordDeclare: false,
declareKeyword: '',
ignoreThisArg: true,
useSplit: true,
declareTemplate: /Solution:\s+def\s+\w+\((.+?)\)/,
template: /^(.+?\s*?\*?)&?\s*(\w+)$/,
},
'JavaScript': {
lang: 'JavaScript',
baseType: ['boolean', 'character', 'number', 'string'],
extendType: [/^ListNode$/],
useArray: true,
arrayBrackets: '[]',
squareBracketsPostPosition: false,
usePointer: false,
useGenerics: false,
useNewForArray: false,
useNewForObject: true,
accessProperty: '.',
nullValue: 'null',
classStructSlice: [2, -1],
commentChar: '*',
singleLineCommentStartsWith: '//',
endsWithSemicolon: true,
typePostPosition: false,
useTypeDeclare: false,
useKeywordDeclare: true,
declareKeyword: 'let',
ignoreThisArg: false,
useSplit: false,
declareTemplate: /\/\*\*(.+?@param.+?)\*\//,
template: /@param\s+{(.+?)}\s+(\w+)/,
},
};
#support;
#config;
/**
* 通过语言类型指定语句解析器
* @param lang {string} 编程语言
*/
constructor(lang) {
if (lang in StatementParser.#conf) {
this.#support = true;
this.#config = StatementParser.#conf[lang];
} else {
this.#support = false;
}
}
/**
* 通过代码和输入直接获得对应声明语句
* @param declares {array[array[string]]} 声明类型及变量名的数组
* @param expressions {array[string]} 声明表达式数组
*/
getStatementsFromDeclaresAndExpressions(declares, expressions) {
let statementCount = declares.length;
let statements = [];
for (let i = 0; i < statementCount; ++i) {
let value = this.parseExpression(expressions[i]);
let [type, name] = declares[i];
statements.push(this.getStatement(type, name, value));
}
return statements.join('\n');
}
/**
* 从代码中获取参数声明
* @param code {string} 代码字符串
* @return {array[string]} 变量声明数组,每个元素为 [类型, 变量名]
*/
getDeclaresFromCode(code) {
code = code.replace(/\n/g, '');
let pattern = this.#config.declareTemplate;
let template = this.#config.template;
let rawDeclares = code.match(pattern)[1];
let declares;
if (this.#config.useSplit) {
declares = rawDeclares.replace(/\s+([&*])\s*/g, '$1 ').split(/\s*,\s*/);
} else {
declares = rawDeclares.match(new RegExp(template, 'g'));
}
if (this.#config.ignoreThisArg)
declares = declares.slice(1);
if (this.#config.useSplit) {
declares = declares.map(pair => pair.split(/:?\s+/));
} else {
declares = declares.map(pair => {
pair = pair.match(template);
return [pair[1], pair[2]];
});
}
if (this.#config.typePostPosition)
declares = declares.map(pair => [pair[1], pair[0]]);
declares.forEach(pair => {
pair[0] = pair[0].replace(/&$/, '');
});
return declares;
}
/**
* 通过类型,变量名,以及字面值,生成赋值表达式
* @param type {string} 类型
* @param name {string} 变量名
* @param value {string} 字面值
* @return {string} 可被解析的赋值表达式
*/
getStatement(type, name, value) {
let strOfDeclare = this.#config.useTypeDeclare ? `${type} ` : (this.#config.useKeywordDeclare ? `${this.#config.declareKeyword} ` : '');
let strOfEnd = this.#config.endsWithSemicolon ? ';' : '';
let [belongsBaseType, baseType, dimension] = this.resolveType(type);
if (belongsBaseType) {
value = this.parseValue(baseType, value, dimension)[0];
return `${strOfDeclare}${name} = ${value}${strOfEnd}`;
} else {
let pattern = this.#findExtendType(type);
if (pattern && pattern.toString().includes('ListNode')) {
let array = value.match(/\d+/g).map(e => parseInt(e));
return this.#makeListNode(name, array);
} else if (pattern && pattern.toString().includes('vector')) {
let elementType = type.match(pattern)[1];
return this.#makeVector(name, elementType, value);
} else if (pattern && pattern.toString().match(/List\\\[.+]/)) {
let elementType = type.match(pattern)[1];
return this.#makeList(name, elementType, value);
}
}
return `${strOfDeclare}${name} = ${this.#config.nullValue}${strOfEnd} ${this.#config.singleLineCommentStartsWith} cannot resolve this type`;
}
/**
* 从代码中获取注释结构类声明代码
* @param code {string} 代码字符串
* @return {string|null} 结构类声明代码,不存在则返回 null
*/
getClassStructFromCode(code) {
let commentChar = this.#config.commentChar;
let [start, end] = this.#config.classStructSlice;
let prefixPattern = new RegExp(`^\\s*${commentChar === '*' ? '\\*' : commentChar}\\s`);
if (commentChar === '*') {
let [matchLeft, matchRight] = [code.match(/\/\*/), code.match(/\*\//)];
if (!matchLeft || !matchRight)
return null;
let [commentStart, commentEnd] = [matchLeft.index, matchRight.index + 2];
let structComment = code.slice(commentStart, commentEnd).split('\n');
structComment = structComment.slice(start, structComment.length + end);
return structComment.map(line => line.replace(prefixPattern, '')).join('\n');
} else if (commentChar === '#') {
let leftIndex = /#/m.exec(code).index;
let rightIndex = /\n[^#]/m.exec(code).index + 1;
let structComment = code.slice(leftIndex, rightIndex).split('\n');
structComment = structComment.slice(start, structComment.length + end);
return structComment.map(line => line.replace(prefixPattern, '')).join('\n').trim();
}
}
/**
* 解析赋值表达式中的被赋予的字面值,无回车无前后空格无末尾逗号
* @param expression 表达式,形式为 "name = value"
* @return {string} 表达式中被赋予的字面值
*/
parseExpression(expression) {
let value;
expression = expression.trim().replace(/,$/, '');
if (expression.includes('=')) {
value = expression.split(/\s*=\s*/)[1];
} else {
value = expression;
}
value = value.replace(/\n/g, '');
return value;
}
/**
* 分析被赋予的字面值
* @param baseType {string} 基本类型
* @param value {string} 被赋予的字面值
* @param dimension {number} 类型维度
* @return {array[string]} 处理后的可解析的可被赋予的值
*/
parseValue(baseType, value, dimension) {
let brackets = this.#config.arrayBrackets.split('');
let extractElementsPattern = /^\[\s*(.*?)\s*]$/;
let extractStringsPattern = /(".*?")/g;
if (dimension === 0) {
if (baseType === 'char' || baseType === 'character') {
if (value.match(/"."/)) {
value = value.replace(/"/g, '\'');
} else if (value.match(/^.$/)) {
value = `'${value}'`;
}
}
return [value, value];
} else if (dimension === 1) {
if (baseType.toLowerCase() === 'string' || baseType === 'str') {
let elements = value.match(extractStringsPattern);
elements = elements || [];
let elementsStr = elements.join(', ');
value = `${brackets[0]}${elementsStr}${brackets[1]}`;
return [value, elements];
} else {
let rawElementsStr = value.match(extractElementsPattern)[1];
let elements = rawElementsStr.split(/\s*,\s*/);
elements = rawElementsStr ? elements : [];
let elementsStr = elements.join(', ');
if (baseType === 'char' || baseType === 'character')
elementsStr = elementsStr.replace(/"/g, '\'');
value = `${brackets[0]}${elementsStr}${brackets[1]}`;
return [value, elements];
}
} else if (dimension === 2) {
if (baseType.toLowerCase() === 'string' || baseType === 'str') {
let strMatrix = StatementParser.#parseStringMatrix(value, '[]');
value = `${brackets[0]}\n\t${strMatrix.map(strArray => {
return `${brackets[0]}${strArray.join(', ')}${brackets[1]}`;
}).join(',\n\t')}\n${brackets[1]}`;
return [value, strMatrix];
} else {
let arraysStr = value.match(extractElementsPattern)[1];
if (!arraysStr)
return [brackets.join(''), []];
let arraysStrFmt = arraysStr.replace(/\s+/g, '').replace(/(],)/g, '$1 ');
let arrayStrs = arraysStrFmt.split(/,\s+/);
let arrayStrFmts = arrayStrs.map(arrayStr => {
let elementsStr = arrayStr.match(extractElementsPattern)[1];
if (baseType === 'char')
elementsStr = elementsStr.replace(/"/g, '\'');
return `${brackets[0]}${elementsStr.replace(/,/g, ', ')}${brackets[1]}`;
});
let realValue = arrayStrs.map(arrayStr => {
let elementsStr = arrayStr.match(extractElementsPattern)[1];
return elementsStr.split(',');
});
value = `${brackets[0]}\n\t${arrayStrFmts.join(',\n\t')}\n${brackets[1]}`;
return [value, realValue];
}
}
return [value, value];
}
/**
* 解析类型,检查是否属于基础类型,以及分析类型的维度
* @param type {string} 类型
* @return {[boolean, string, number]} 是否属于基本类型,解析后的基本类型,类型维度
*/
resolveType(type) {
let dimension = 0;
if (type.endsWith('[][]')) {
type = type.slice(0, type.length - 4);
dimension = 2;
} else if (type.endsWith('[]')) {
type = type.slice(0, type.length - 2);
dimension = 1;
}
let isBaseType = !!this.#findBaseType(type);
return [isBaseType, type, dimension];
}
/**
* 判断类型是否在基本类型中,并返回匹配到的基本类型,匹配失败返回 null
* @param type {string} 类型
* @return {string|null} 匹配到的基本类型,或 null
*/
#findBaseType(type) {
let index = this.#config.baseType.indexOf(type);
if (index < 0)
return null;
return this.#config.baseType[index];
}
/**
* 判断类型是否在扩展类型中,并返回匹配到的扩展类型,匹配失败返回 null
* @param type {string} 类型
* @return {RegExp|null} 匹配到的扩展类型,或 null
*/
#findExtendType(type) {
for (let pattern of this.#config.extendType)
if (type.match(pattern))
return pattern;
return null;
}
/**
* 通过链表元素生成链表声明语句
* @param name {string} 变量名
* @param array {array[number]} 链表的所有元素
* @return {string} 链表声明语句集合的字符串
*/
#makeListNode(name, array) {
let strOfPtr = this.#config.usePointer ? '*' : '';
let strOfDeclare = this.#config.useTypeDeclare ? `ListNode${strOfPtr} ` : (this.#config.useKeywordDeclare ? `${this.#config.declareKeyword} ` : '');
let strOfNew = this.#config.useNewForObject ? 'new ' : '';
let strOfNullValue = this.#config.nullValue;
let strOfNext = this.#config.accessProperty;
let strOfEnd = this.#config.endsWithSemicolon ? ';' : '';
if (array.length === 0)
return `${strOfDeclare}${name} = ${strOfNullValue}${strOfEnd}`;
let statementList = [`${strOfDeclare}${name} = ${strOfNew}ListNode(${array[0]})${strOfEnd}`];
if (array.length === 1)
return statementList[0];
statementList.push(`${strOfDeclare}${name}Next = ${name}${strOfEnd}`);
for (let i = 1; i < array.length; ++i) {
statementList.push(`${name}Next${strOfNext}next = ${strOfNew}ListNode(${array[i]})${strOfEnd}`);
if (i + 1 < array.length)
statementList.push(`${name}Next = ${name}Next${strOfNext}next${strOfEnd}`);
}
return statementList.join('\n');
}
/**
* 通过变量名,元素类型,以及字面值生成 vector 的赋值表达式
* @param name {string} vector 变量名
* @param elementType {string} 元素类型
* @param value {string} 已处理的被赋值字面值
* @return {string} 可被解析的赋值表达式
*/
#makeVector(name, elementType, value) {
if (this.#findBaseType(elementType)) {
// vector<baseType>
let formatValue = this.parseValue(elementType, value, 1)[0];
return `vector<${elementType}> ${name} ${formatValue};`;
} else {
// vector<...>
let pattern = this.#findExtendType(elementType);
if (pattern && pattern.toString().includes('vector')) {
// vector<vector<...>>
let baseType = elementType.match(pattern)[1];
if (this.#findBaseType(baseType)) {
// vector<vector<baseType>>
let matrix = this.parseValue(baseType, value, 2)[1];
let [row, col] = [matrix.length, matrix[0].length];
let statements = [
`vector<vector<${baseType}>> ${name};`,
`${baseType} ${name}Matrix[${row}][${col}] = {`
];
for (let i = 0; i < row; ++i) {
let rowInitValues = `{${matrix[i].join(', ')}}`;
if (i + 1 < row)
rowInitValues += ',';
statements.push(rowInitValues);
}
statements.push(`};`);
statements.push(`for (int ${name}RowIndex = 0; ${name}RowIndex < ${row}; ++${name}RowIndex) {`);
statements.push(`\tvector<${baseType}> ${name}Row(begin(${name}Matrix[${name}RowIndex]), end(${name}Matrix[${name}RowIndex]));`);
statements.push(`\t${name}.push_back(${name}Row);`);
statements.push(`};`);
return statements.join('\n');
}
}
}
return `vector<${elementType}> ${name}; // cannot resolve this type`;
}
/**
* 通过变量名,元素类型,以及字面值生成 List 的赋值表达式
* @param name {string} vector 变量名
* @param elementType {string} 元素类型
* @param value {string} 已处理的被赋值字面值
* @return {string} 可被解析的赋值表达式
*/
#makeList(name, elementType, value) {
if (this.#findBaseType(elementType)) {
// List[baseType]
let formatValue = this.parseValue(elementType, value, 1)[0];
return `${name} = ${formatValue}`;
} else {
// List[...]
let pattern = this.#findExtendType(elementType);
if (pattern && pattern.toString().match(/List\\\[.+]/)) {
// List[List[...]]
let baseType = elementType.match(pattern)[1];
if (this.#findBaseType(baseType)) {
// List[List[baseType]]
let formatValue = this.parseValue(baseType, value, 2)[0];
return `${name} = ${formatValue}`;
}
}
}
return `${name} = None # cannot resolve this type`;
}
/**
* 搜索字符串中首个
* @param str {string} 需要搜索的字符串
* @param brackets {string} 括号类型
* @param start {number} 开始搜索的索引
* @return {array[number]} 返回搜索到的首对最外层括号的索引
*/
static #findBrackets(str, brackets, start) {
let stack = [], left = start, length = str.length;
let [l, r] = brackets.split('');
while (left < length && str[left] !== l)
++left;
if (left >= length)
return [-1, -1];
let right = left;
while (right < length) {
let c = str[right];
let peekElement = stack[stack.length - 1];
if (c === l) {
if (peekElement === '"') {
++right;
continue;
} else {
stack.push(c);
}
} else if (c === '"') {
if (peekElement === '"') {
stack.pop();
} else {
stack.push(c);
}
} else if (c === r) {
if (peekElement === '"') {
++right;
continue;
} else if (peekElement === l) {
stack.pop();
if (stack.length === 0)
return [left, right];
}
}
++right;
}
return [-1, -1];
}
/**
* 解析二维字符串数组字面值为真实二维数组
* @param value {string} 二维字符串数组字面值
* @param brackets {string} 括号类型
* @return {array[array[string]]} 二维字符串数组
*/
static #parseStringMatrix(value, brackets) {
let extractElementsPattern = new RegExp(`^\\${brackets[0]}\\s*(.+?)\\s*${brackets[1]}$`);
let extractStringsPattern = /(".*?")/g;
let rawArraysStr = value.match(extractElementsPattern)[1];
let index = 0, strMatrix = [];
let [left, right] = StatementParser.#findBrackets(rawArraysStr, brackets, index);
while (left >= 0 && right >= 0) {
let arrayStr = rawArraysStr.slice(left, right + 1);
let strArray = arrayStr.match(extractStringsPattern);
strMatrix.push(strArray);
index = right + 1;
[left, right] = StatementParser.#findBrackets(rawArraysStr, brackets, index);
}
return strMatrix;
}
}
window.StatementParser = StatementParser;
})();