{
// Command calculator is a small PEG-generated parser that computes
// simple math using integers.
//
// Example usage: $ calculator "3 + (2 - 5 * 12)"
//
// Inspired by pegjs arithmetic example:
// https://github.com/pegjs/pegjs/blob/master/examples/arithmetics.pegjs
//
package main

var ops = map[string]func(int, int) int {
    "+": func(l, r int) int {
        return l + r
    },
    "-": func(l, r int) int {
        return l - r
    },
    "*": func(l, r int) int {
        return l * r
    },
    "/": func(l, r int) int {
        return l / r
    },
}

// for testing purpose
var cntCodeBlocks int

func main() {
    if len(os.Args) != 2 {
        log.Fatal("Usage: calculator 'EXPR'")
    }
    got, err := ParseReader("", strings.NewReader(os.Args[1]))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("=", got)
}

func toIfaceSlice(v interface{}) []interface{} {
    if v == nil {
        return nil
    }
    return v.([]interface{})
}

func eval(first, rest interface{}) int {
    l := first.(int)
    restSl := toIfaceSlice(rest)
    for _, v := range restSl {
        restExpr := toIfaceSlice(v)
        r := restExpr[3].(int)
        op := restExpr[1].(string)
        l = ops[op](l, r)
    }
    return l
}
}

Input <- expr:Expr EOF {
    cntCodeBlocks++
    return expr, nil
}

Expr <- _ first:Term rest:( _ AddOp _ Term )* _ {
    cntCodeBlocks++
    return eval(first, rest), nil
}

Term <- first:Factor rest:( _ MulOp _ Factor )* {
    cntCodeBlocks++
    return eval(first, rest), nil
}

Factor <- '(' expr:Expr ')' {
    cntCodeBlocks++
    return expr, nil
} / integer:Integer {
    cntCodeBlocks++
    return integer, nil
}

AddOp <- ( '+' / '-' ) {
    cntCodeBlocks++
    return string(c.text), nil
}

MulOp <- ( '*' / '/' ) {
    cntCodeBlocks++
    return string(c.text), nil
}

Integer <- '-'? [0-9]+ {
    cntCodeBlocks++
    return strconv.Atoi(string(c.text))
}

_ "whitespace" <- [ \n\t\r]*

EOF <- !.
