lf/parse.go

269 lines
4.2 KiB
Go
Raw Normal View History

2016-08-13 12:49:04 +00:00
package main
// Grammar of the language used in the evaluator
//
// Expr = SetExpr
// | MapExpr
// | CMapExpr
2016-08-13 12:49:04 +00:00
// | CmdExpr
// | CallExpr
// | ExecExpr
// | ListExpr
//
// SetExpr = 'set' <opt> <val> ';'
//
// MapExpr = 'map' <keys> Expr ';'
//
// CMapExpr = 'cmap' <key> <cmd> ';'
//
2016-08-13 12:49:04 +00:00
// CmdExpr = 'cmd' <name> Expr ';'
//
// CallExpr = <name> <args> ';'
//
// ExecExpr = Prefix <expr> '\n'
// | Prefix '{{' <expr> '}}' ';'
//
// Prefix = '$' | '!' | '&' | '/' | '?'
//
// ListExpr = ':' ListRest '\n'
2016-08-13 12:49:04 +00:00
// | ':' '{{' ListRest '}}' ';'
//
// ListRest = Nil
// | Expr ListRest
import (
"fmt"
"io"
)
2016-12-17 21:47:37 +00:00
type expr interface {
2016-08-13 12:49:04 +00:00
String() string
2016-12-17 21:47:37 +00:00
eval(app *app, args []string)
2016-08-13 12:49:04 +00:00
// TODO: add a bind method to avoid passing args in eval
}
2016-12-17 21:47:37 +00:00
type setExpr struct {
2016-08-13 12:49:04 +00:00
opt string
val string
}
2016-12-17 21:47:37 +00:00
func (e *setExpr) String() string { return fmt.Sprintf("set %s %s", e.opt, e.val) }
2016-08-13 12:49:04 +00:00
2016-12-17 21:47:37 +00:00
type mapExpr struct {
2016-08-13 12:49:04 +00:00
keys string
2016-12-17 21:47:37 +00:00
expr expr
2016-08-13 12:49:04 +00:00
}
2016-12-17 21:47:37 +00:00
func (e *mapExpr) String() string { return fmt.Sprintf("map %s %s", e.keys, e.expr) }
2016-08-13 12:49:04 +00:00
type cmapExpr struct {
key string
cmd string
}
func (e *cmapExpr) String() string { return fmt.Sprintf("cmap %s %s", e.key, e.cmd) }
2016-12-17 21:47:37 +00:00
type cmdExpr struct {
2016-08-13 12:49:04 +00:00
name string
2016-12-17 21:47:37 +00:00
expr expr
2016-08-13 12:49:04 +00:00
}
2016-12-17 21:47:37 +00:00
func (e *cmdExpr) String() string { return fmt.Sprintf("cmd %s %s", e.name, e.expr) }
2016-08-13 12:49:04 +00:00
2016-12-17 21:47:37 +00:00
type callExpr struct {
2016-08-13 12:49:04 +00:00
name string
args []string
}
2016-12-17 21:47:37 +00:00
func (e *callExpr) String() string { return fmt.Sprintf("%s -- %s", e.name, e.args) }
2016-08-13 12:49:04 +00:00
2016-12-17 21:47:37 +00:00
type execExpr struct {
2016-08-13 12:49:04 +00:00
pref string
expr string
}
2016-12-17 21:47:37 +00:00
func (e *execExpr) String() string { return fmt.Sprintf("%s %s", e.pref, e.expr) }
2016-08-13 12:49:04 +00:00
2016-12-17 21:47:37 +00:00
type listExpr struct {
exprs []expr
2016-08-13 12:49:04 +00:00
}
2016-12-17 21:47:37 +00:00
func (e *listExpr) String() string {
2016-08-13 12:49:04 +00:00
buf := []byte{':', '{', '{', ' '}
for _, expr := range e.exprs {
buf = append(buf, expr.String()...)
buf = append(buf, ';', ' ')
}
buf = append(buf, '}', '}')
return string(buf)
}
2016-12-17 21:47:37 +00:00
type parser struct {
scanner *scanner
expr expr
2016-08-13 12:49:04 +00:00
err error
}
2016-12-17 21:47:37 +00:00
func newParser(r io.Reader) *parser {
2016-08-13 12:49:04 +00:00
scanner := newScanner(r)
scanner.scan()
2016-12-17 21:47:37 +00:00
return &parser{
2016-08-13 12:49:04 +00:00
scanner: scanner,
}
}
2016-12-17 21:47:37 +00:00
func (p *parser) parseExpr() expr {
2016-08-13 12:49:04 +00:00
s := p.scanner
2016-12-17 21:47:37 +00:00
var result expr
2016-08-13 12:49:04 +00:00
switch s.typ {
2016-12-17 21:47:37 +00:00
case tokenEOF:
2016-08-13 12:49:04 +00:00
return nil
2016-12-17 21:47:37 +00:00
case tokenIdent:
2016-08-13 12:49:04 +00:00
switch s.tok {
case "set":
2016-10-16 11:19:19 +00:00
var val string
2016-08-13 12:49:04 +00:00
s.scan()
2016-12-17 21:47:37 +00:00
if s.typ != tokenIdent {
2016-10-16 11:19:19 +00:00
p.err = fmt.Errorf("expected identifier: %s", s.tok)
}
2016-08-13 12:49:04 +00:00
opt := s.tok
s.scan()
2016-12-17 21:47:37 +00:00
if s.typ != tokenSemicolon {
2016-08-13 12:49:04 +00:00
val = s.tok
s.scan()
}
s.scan()
2016-12-17 21:47:37 +00:00
result = &setExpr{opt, val}
2016-08-13 12:49:04 +00:00
case "map":
2016-12-17 21:47:37 +00:00
var expr expr
2016-08-13 12:49:04 +00:00
s.scan()
keys := s.tok
s.scan()
2016-12-17 21:47:37 +00:00
if s.typ != tokenSemicolon {
expr = p.parseExpr()
} else {
s.scan()
}
2016-08-13 12:49:04 +00:00
2016-12-17 21:47:37 +00:00
result = &mapExpr{keys, expr}
case "cmap":
var cmd string
s.scan()
key := s.tok
s.scan()
if s.typ != tokenSemicolon {
if s.typ != tokenIdent {
p.err = fmt.Errorf("expected command: %s", s.tok)
}
cmd = s.tok
s.scan()
}
s.scan()
result = &cmapExpr{key, cmd}
2016-08-13 12:49:04 +00:00
case "cmd":
2016-12-17 21:47:37 +00:00
var expr expr
2016-08-13 12:49:04 +00:00
s.scan()
name := s.tok
s.scan()
2016-12-17 21:47:37 +00:00
if s.typ != tokenSemicolon {
expr = p.parseExpr()
} else {
s.scan()
}
2016-08-13 12:49:04 +00:00
2016-12-17 21:47:37 +00:00
result = &cmdExpr{name, expr}
2016-08-13 12:49:04 +00:00
default:
name := s.tok
var args []string
2016-12-17 21:47:37 +00:00
for s.scan() && s.typ != tokenSemicolon {
2016-08-13 12:49:04 +00:00
args = append(args, s.tok)
}
s.scan()
2016-12-17 21:47:37 +00:00
result = &callExpr{name, args}
2016-08-13 12:49:04 +00:00
}
2016-12-17 21:47:37 +00:00
case tokenColon:
2016-08-13 12:49:04 +00:00
s.scan()
2016-12-17 21:47:37 +00:00
var exprs []expr
if s.typ == tokenLBraces {
2016-08-13 12:49:04 +00:00
s.scan()
for {
e := p.parseExpr()
if e == nil {
return nil
}
exprs = append(exprs, e)
2016-12-17 21:47:37 +00:00
if s.typ == tokenRBraces {
2016-08-13 12:49:04 +00:00
break
}
}
s.scan()
} else {
for {
e := p.parseExpr()
if e == nil {
return nil
}
exprs = append(exprs, e)
if s.tok == "\n" {
break
}
}
}
s.scan()
2016-12-17 21:47:37 +00:00
result = &listExpr{exprs}
case tokenPrefix:
2016-10-16 11:19:19 +00:00
var expr string
2016-08-13 12:49:04 +00:00
pref := s.tok
s.scan()
2016-12-17 21:47:37 +00:00
if s.typ == tokenLBraces {
2016-08-13 12:49:04 +00:00
s.scan()
expr = s.tok
s.scan()
} else {
2016-10-16 11:19:19 +00:00
expr = s.tok
2016-08-13 12:49:04 +00:00
}
s.scan()
s.scan()
2016-12-17 21:47:37 +00:00
result = &execExpr{pref, expr}
2016-08-13 12:49:04 +00:00
default:
2016-10-16 11:19:19 +00:00
p.err = fmt.Errorf("unexpected token: %s", s.tok)
2016-08-13 12:49:04 +00:00
}
return result
}
2016-12-17 21:47:37 +00:00
func (p *parser) parse() bool {
2016-08-13 12:49:04 +00:00
if p.expr = p.parseExpr(); p.expr == nil {
return false
}
return true
}