parseSource

function parseSource(fs, file_name)

ソースファイルの構文解析

ソース

function parseSource(fs, file_name) {
    var source_file = new SourceFile(file_name);
    SourceFiles.push(source_file);

    fs.mkdirsSync('../docs/api/' + file_name);

    console.log(file_name);

    var buf = fs.readFileSync(file_name + ".js");
    var str = buf.toString().replace(/\r\n/g, "\n").replace(/\t/g, "    ").replace(/[ ]+$/g, "");

    var class_name = null;
    var class_indent = -1;
    var current_class = null;
    var current_fnc = null;
    var comment_start = null;
    var comment_indent;
    var comment = null;
    var prev_comment = null;

    var lines = str.split('\n');
    for (var line_idx = 0; line_idx < lines.length; line_idx++) {
        if (prev_comment != null) {

            comment = prev_comment;
            prev_comment = null;
        }
        else {
            comment = null;
        }


        var line = lines[line_idx];
        if (line.trim().length == 0) {
            // 空行の場合

            if (source_file.comment == null && comment != null) {

                source_file.comment = comment;
            }

            continue;
        }

        var indent = SkipSpace(line, 0);

        if (comment_start != null) {

            if (line.startsWith("*/", indent)) {
                prev_comment = lines.slice(comment_start + 1, line_idx).map(x => x.substring(comment_indent)).join("\n");
                comment_start = null;
            }

            continue;
        }

        if (line.startsWith("class", indent)) {
            // クラスの場合

            var pos = SkipSpace(line, indent + 5);
            [pos, class_name] = SkipName(line, pos);

            pos = SkipSpace(line, pos);

            var super_class_name = null;
            if (line.startsWith("extends", pos)) {

                pos = SkipSpace(line, pos + 7);

                [pos, super_class_name] = SkipName(line, pos);
            }

            current_class = new Class(source_file, comment, indent, class_name, super_class_name);
            source_file.classes.push(current_class);
            Classes.push(current_class);
        }
        else if (line.startsWith("/**", indent) || line.startsWith("/*", indent)) {
            // ブロックコメントの場合

            var s = line.trim();
            if (s.endsWith("*/")) {

                comment_indent = 0;
                prev_comment = s.substring(2, s.length - 2);
            }
            else {

                comment_indent = indent;
                comment_start = line_idx;
            }
        }
        else if (line.startsWith("//", indent)) {
            // 行コメントの場合

            prev_comment = line.substring(indent + 2).trim();
        }
        else if (line.startsWith("function", indent)) {
            // 関数の場合

            var pos = SkipSpace(line, indent + 8);
            var fnc_name;

            [pos, fnc_name] = SkipName(line, pos);

            current_fnc = new Function(comment, line_idx, line, indent, false, fnc_name, null);
            source_file.functions.push(current_fnc);
        }
        else if (line.startsWith("constructor", indent)) {
            // コンストラクタの場合

            current_fnc = new Function(comment, line_idx, line, indent, false, "constructor", current_class);
            current_class.methods.push(current_fnc);
        }
        else if (line.startsWith("var", indent)) {
            // 変数の場合

        }
        else if (line.startsWith("}", indent)) {
            // ブロックの終わりの場合

            if (current_class != null && current_class.indent == indent) {

                current_class = null;
            }
            else if (current_fnc != null && current_fnc.indent == indent) {

                current_fnc.body = "    " + lines.slice(current_fnc.startLineIdx, line_idx + 1).join("\n    ");

                current_fnc = null;
            }

        }
        else {

            if (current_class != null && current_class.indent + 4 == indent && current_fnc == null) {
                // クラス定義の中で、クラス定義の直下のインデントで、関数定義の中でない場合

                var pos, fnc_name, is_generator = false;

                if (line[indent] == "*") {
                    // ジェネレーターの場合

                    is_generator = true;

                    pos = SkipSpace(line, indent + 1);
                }
                else {
                    // ジェネレーターでない場合

                    pos = indent;
                }

                [pos, fnc_name] = SkipName(line, pos);

                current_fnc = new Function(comment, line_idx, line, indent, is_generator, fnc_name, current_class);
                current_class.methods.push(current_fnc);
            }

        }
    }
}