mna / pigeon

Command pigeon generates parsers in Go from a PEG grammar.
BSD 3-Clause "New" or "Revised" License
822 stars 66 forks source link

[Feature Request] Skip all "codeExpr" while looking ahead #149

Open fy0 opened 2 months ago

fy0 commented 2 months ago

For example:

aExpr <- &('-' number) stateChange '-' number { c.globalState["code"].push(vmCode(typeUnaryMinus)) }

stateChange <- #{ c.globalState['minus'] += 1 }

number <- [0-9]+ { c.globalState["code"].push(newIntVal(c.text)); }

Many script languages are not generate ast, instead of write code directly.

In this example, i want to check if - number is matched, then make state change.

But c.globalState["code"].push(newIntVal(c.text)) is invoked while looking ahead of "- number". I think it could use some improvement.

There's a simple patch:

// edit parseAndExpr:

func (p *parser) parseAndExpr(and *andExpr) (any, bool) {
    pt := p.pt
    state := p.cloneState()
    p.pushV()
    p.cur.state["skipCode"] = true
    _, ok := p.parseExprWrap(and.expr)
    delete(p.cur.state, "skipCode")
    p.popV()
    p.restoreState(state)
    p.restore(pt)

    return nil, ok
}

// edit parseActionExpr:
func (p *parser) parseActionExpr(act *actionExpr) (any, bool) {
    if p.cur.state["skipCode"] == true {
        return nil, true
    }
    start := p.pt
    val, ok := p.parseExprWrap(act.expr)
    if ok {
        .....
}

Do same thing to parseOrExpr and other codeExpr.