lf/parse.go

302 lines
4.5 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> ';'
//
2017-11-19 18:55:13 +00:00
// MapExpr = 'map' <keys> Expr
2016-08-13 12:49:04 +00:00
//
// CMapExpr = 'cmap' <key> <cmd> ';'
//
2017-11-19 18:55:13 +00:00
// CmdExpr = 'cmd' <name> Expr
2016-08-13 12:49:04 +00:00
//
// CallExpr = <name> <args> ';'
//
2017-11-19 18:55:13 +00:00
// ExecExpr = Prefix <value> '\n'
// | Prefix '{{' <value> '}}' ';'
2016-08-13 12:49:04 +00:00
//
2018-05-20 17:30:41 +00:00
// Prefix = '$' | '%' | '!' | '&'
2016-08-13 12:49:04 +00:00
//
2017-11-19 18:55:13 +00:00
// ListExpr = ':' Expr ListRest '\n'
// | ':' '{{' Expr ListRest '}}' ';'
2016-08-13 12:49:04 +00:00
//
// ListRest = Nil
2017-11-19 18:55:13 +00:00
// | Expr ListExpr
2016-08-13 12:49:04 +00:00
import (
"bytes"
2016-08-13 12:49:04 +00:00
"fmt"
"io"
"strings"
2016-08-13 12:49:04 +00:00
)
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
}
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 {
name string
args []string
count int
2016-08-13 12:49:04 +00:00
}
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 {
2017-11-19 18:55:13 +00:00
prefix string
value string
2016-08-13 12:49:04 +00:00
}
func (e *execExpr) String() string {
var buf bytes.Buffer
2017-11-19 18:55:13 +00:00
buf.WriteString(e.prefix)
buf.WriteString("{{ ")
2017-11-19 18:55:13 +00:00
lines := strings.Split(e.value, "\n")
for _, line := range lines {
trimmed := strings.TrimSpace(line)
if trimmed == "" {
continue
}
buf.WriteString(trimmed)
if len(lines) > 1 {
buf.WriteString(" ...")
}
break
}
buf.WriteString(" }}")
return buf.String()
}
2016-08-13 12:49:04 +00:00
2016-12-17 21:47:37 +00:00
type listExpr struct {
exprs []expr
count int
2016-08-13 12:49:04 +00:00
}
2016-12-17 21:47:37 +00:00
func (e *listExpr) String() string {
2017-11-04 15:58:48 +00:00
var buf bytes.Buffer
buf.WriteString(":{{ ")
2016-08-13 12:49:04 +00:00
for _, expr := range e.exprs {
2017-11-04 15:58:48 +00:00
buf.WriteString(expr.String())
buf.WriteString("; ")
2016-08-13 12:49:04 +00:00
}
2017-11-04 15:58:48 +00:00
buf.WriteString("}}")
return buf.String()
2016-08-13 12:49:04 +00:00
}
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()
result = &callExpr{name, args, 1}
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()
result = &listExpr{exprs, 1}
2016-12-17 21:47:37 +00:00
case tokenPrefix:
2016-10-16 11:19:19 +00:00
var expr string
2017-11-19 18:55:13 +00:00
prefix := s.tok
2016-08-13 12:49:04 +00:00
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()
2017-11-19 18:55:13 +00:00
result = &execExpr{prefix, 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
}