evaera / moonwave

Moonwave is a tool for generating documentation from comments in Lua source code.
https://eryn.io/moonwave/
Mozilla Public License 2.0
151 stars 23 forks source link

LuaType.js not correctly parsing some complex values #133

Open probablytukars opened 11 months ago

probablytukars commented 11 months ago

I was using LuaType.js for a personal project, and in my testing I found that there were some parsing errors, luckily I was able to make a fix, but note that some of the variables are changed.


const print = console.log

const isPunc = (char) => !!char.match(/[\{\}<>\-\|&<>()\[\]]/)
const isAtom = (char) => !isPunc(char)

function _tokenize(code, isGroup) {
    print("reading", code)

    let position = 0
    const tokens = []

    const next = () => code[position++]
    const peek = () => code[position]

    const read = (condition) => {
        let buffer = ""
        while (peek() && condition(peek())) {buffer += next()}
        return buffer
    }

    const readBalanced = (left, right) => {
        let buffer = ""
        let depth = 0
        while (peek()) {
            if (peek() === left) {
                depth++
            } else if (peek() === right) {
                if (depth === 0) {
                    break
                } else {
                    depth--
                }
            }
            buffer += next()
        }
        return buffer
    }

    while (position < code.length) {
        if (peek() === "(") {
            position++
            tokens.push({
                type: "tuple",
                within: _tokenize(readBalanced("(", ")"), true)
            })
            next()
            continue
        }

        if (peek() === "[") {
            next()
            tokens.push({
                type: "indexer",
                within: _tokenize(readBalanced("[", "]")),
            })
            next()
            continue
        }

        if (peek() === "{") {
            next()
            tokens.push({
                type: "table",
                within: _tokenize(readBalanced("{", "}"), true),
            })
            next()
            continue
        }

        if (isGroup && peek() === ",") {
            next()
            tokens.push({
              type: "separator",
            })
            continue
          }

        if (isPunc(peek())) {
            const punc = next()

            if (punc === "-" && peek() === ">") {
                tokens.push({
                    type: "arrow",
                })
                next()
                continue
            }

            if (punc === "|") {
                tokens.push({ type: "union" })
                continue
            }

            if (punc === "&") {
                tokens.push({ type: "intersection" })
                continue
            }

            tokens.push({
                type: "punc",
                punc,
            })
            continue
        }

        const atom = read((char) =>
            isGroup ? char !== "," && isAtom(char) : isAtom(char)
        )

        if (atom) {
            if (atom.endsWith(":")) {
                tokens.push({ type: "identifier", identifier: atom.slice(0, -1) })
            } else {
                tokens.push({
                    type: "luaType",
                    luaType: atom,
                })
            }
            continue
        }
    }

    return tokens
}

function getTokens(code) {
    const noWhitespace = code.replace(/\s/g, '')
    return _tokenize(noWhitespace)
}

var advanced_test = "(callback:<T>(internal:(k:{string&number})->T)->string)->{string|number}"

print(JSON.stringify(getTokens(advanced_test), null, 4))

I believe the only parts I changed are adding support for intersection type, and expanding the isPunc function to correctly catch all punctuation, otherwise it can fail on sub-types, of course in my test I removed whitespace before parsing, but adding these modifications it should still work with whitespace.

evaera commented 11 months ago

This isn't the correct way to contribute to an open source project. Pull Requests are for submitting changes, not issues. And it's a good idea to include the cases that are failing in your issue to justify why the change needs to be made, rather than just saying that it does. I can't do anything with this code you've given me.

probablytukars commented 11 months ago

Sorry, never created a pull request before, but I created one now and the dif is only 7 characters and includes the use case where it broke too, hope this is ok!

YetAnotherClown commented 1 month ago

@probablytukars I noticed that you deleted your Pull Request. If you would be interested in opening it again, I'll look into it and merge it if approved.