Statement Parser

【使用前先看介绍/有问题可反馈】声明解析器 (Statement Parser):通过语言,类型,变量名,以及赋值,直接生成可被解析的声明语句。

目前為 2021-09-15 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Statement Parser
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  【使用前先看介绍/有问题可反馈】声明解析器 (Statement Parser):通过语言,类型,变量名,以及赋值,直接生成可被解析的声明语句。
// @author       cc
// @include      *
// @grant        none
// ==/UserScript==

(function() {
    const __VERSION__ = '1.0.1';
    class StatementParser {
        static __VERSION__ = __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,
                useNew: true,
                accessProperty: '.',
                nullValue: 'null',
                classStructSlice: [2, -1],
                commentChar: '*',
                endsWithSemicolon: true,
                typePostPosition: false,
                useTypeDeclare: true,
                ignoreThisArg: false,
                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\*$/, /^vector<(.+)>$/],
                useArray: false,
                arrayBrackets: '{}',
                squareBracketsPostPosition: true,
                usePointer: true,
                useGenerics: true,
                useNew: true,
                accessProperty: '->',
                nullValue: 'NULL',
                classStructSlice: [2, -1],
                commentChar: '*',
                endsWithSemicolon: true,
                typePostPosition: false,
                useTypeDeclare: true,
                ignoreThisArg: false,
                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,
                useNew: false,
                accessProperty: '.',
                nullValue: 'None',
                classStructSlice: [1, 0],
                commentChar: '#',
                endsWithSemicolon: false,
                typePostPosition: true,
                useTypeDeclare: false,
                ignoreThisArg: true,
                declareTemplate: /Solution:\s+def\s+\w+\((.+?)\)/,
                template: /^(.+?\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 {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} 代码字符串
         * @returns {array[string]} 变量声明数组,每个元素为 [类型, 变量名]
         */
        getDeclaresFromCode(code) {
            code = code.replace(/\n/g, '');
            let pattern = this.#config.declareTemplate;
            let rawDeclares = code.match(pattern)[1];
            let declares = rawDeclares.replace(/\s+([&*])\s*/g, '$1 ').split(/\s*,\s*/);
            if (this.#config.ignoreThisArg)
                declares = declares.slice(1);
            declares = declares.map(pair => pair.split(/:?\s+/));
            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} 字面值
         * @returns {string} 可被解析的赋值表达式
         */
        getStatement(type, name, value) {
            let useTypeDeclare = this.#config.useTypeDeclare;
            let endsWithSemicolon = this.#config.endsWithSemicolon;
            let strOfDeclare = this.#config.useTypeDeclare ? `${type} ` : '';
            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 `${type} ${name}; // cannot resolve this type`;
        }

        /**
         * 从代码中获取注释结构类声明代码
         * @param code {string} 代码字符串
         * @returns {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"
         * @returns {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} 类型维度
         * @returns {array[string|any]} 处理后的可解析的可被赋予的值
         */
        parseValue(baseType, value, dimension) {
            let brackets = this.#config.arrayBrackets.split('');
            let extractElementsPattern = /^\[\s*(.+?)\s*]$/;
            let extractStringsPattern = /(".*?")/g;
            let CommaTrimPattern = /\s*,\s*/g;
            if (dimension === 0) {
                if (baseType === 'char') {
                    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);
                    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*/);
                    let elementsStr = elements.join(', ');
                    if (baseType === 'char')
                        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];
                    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} 类型
         * @returns {[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} 类型
         * @returns {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} 类型
         * @returns {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]} 链表的所有元素
         * @returns {string} 链表声明语句集合的字符串
         */
        #makeListNode(name, array) {
            let strOfPtr = this.#config.usePointer ? '*' : '';
            let strOfDeclare = this.#config.useTypeDeclare ? `ListNode${strOfPtr} ` : '';
            let strOfNew = this.#config.useNew ? '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} 已处理的被赋值字面值
         * @returns {string} 可被解析的赋值表达式
         */
        #makeVector(name, elementType, value) {
            if (this.#findBaseType(elementType)) {
                // vector<baseType>
                let [formatValue, realValue] = this.parseValue(elementType, value, 1);
                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 [formatValue, matrix] = this.parseValue(baseType, value, 2);
                        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 = `\t{${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} 已处理的被赋值字面值
         * @returns {string} 可被解析的赋值表达式
         */
        #makeList(name, elementType, value) {
            if (this.#findBaseType(elementType)) {
                // List[baseType]
                let [formatValue, realValue] = this.parseValue(elementType, value, 1);
                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 value {string} 二维数组字面值
         * @returns {[number, number, array[string]]} 二维数组的行,列,以及每一行初始值的字符串列表
         */
        static #getMatrixInfo(value) {
            value = value.replace(/\n/g, '');
            let arrays = value.match(/^{\s*(.+?)\s*}$/)[1].match(/{(.+?)}/g);
            let [row, col] = [arrays.length, arrays[0].match(/".+?"/g).length];
            return [row, col, arrays];
        }

        /**
         * 搜索字符串中首个
         * @param str {string} 需要搜索的字符串
         * @param brackets {string} 括号类型
         * @param start {number} 开始搜索的索引
         * @returns {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} 括号类型
         * @returns {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;
})();