go-calc/calc/cli/cli.go

206 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cli
import (
"errors"
"fmt"
"regexp"
"strings"
"gitea.zaclys.com/bvaudour/gob/number"
"gitea.zaclys.com/bvaudour/gob/option"
"gitea.zaclys.net/bvaudour/calc/calc"
)
type Cli struct {
c *calc.Calc
macros map[string]string
needMacro bool
macro []string
needAlt bool
alt []string
}
func New() *Cli {
c := Cli{
c: calc.New(),
macros: make(map[string]string),
}
return &c
}
func (c *Cli) beginMacro() (err option.Option[error]) {
if c.needMacro {
return option.Some(errors.New("Les macros imbriquées ne sont pas supportées"))
}
c.needMacro = true
return
}
func (c *Cli) addMacro(arg string) (err option.Option[error]) {
if !c.needMacro {
return option.Some(errors.New("La macro na pas commencé…"))
}
c.macro = append(c.macro, arg)
return
}
func (c *Cli) endMacro(k string) (err option.Option[error]) {
macro, fields, needMacro := "[ ]", make([]string, len(c.macro)), c.needMacro
copy(fields, c.macro)
c.resetMacro()
if len(fields) > 0 {
macro = fmt.Sprintf("[ %s ]", strings.Join(fields, " "))
}
if !needMacro {
return option.Some(errors.New("La macro na pas commencé…"))
} else if c.needAlt {
return c.addAlt(fmt.Sprintf("%s%s", macro, k))
} else if len(fields) == 0 {
c.macros[k] = macro
c.c.StoreMacro(k, calc.MacroCommand(calc.NoAction))
return
}
cmds := make([]calc.MacroElement, len(fields))
for i, f := range fields {
result := c.parse(f)
if me, ok := result.Ok(); ok {
cmds[i] = me
} else if e, ok := result.Err(); ok {
return option.Some(e)
}
}
c.macros[k] = macro
c.c.StoreMacro(k, cmds...)
return
}
func (c *Cli) removeMacro(k string) (err option.Option[error]) {
if err = c.c.ResetMacro(k); !err.IsDefined() {
delete(c.macros, k)
}
return
}
func (c *Cli) removeMacros() (err option.Option[error]) {
if err = c.c.ResetMacros(); !err.IsDefined() {
c.macros = make(map[string]string)
}
return
}
func (c *Cli) beginAlt() (err option.Option[error]) {
if c.needAlt {
err = option.Some(errors.New("Les alternatives imbriquées ne sont pas supportées"))
} else {
c.needAlt = true
}
return
}
func (c *Cli) addAlt(arg string) (err option.Option[error]) {
if !c.needAlt {
return option.Some(errors.New("Lalternative nest pas commencée…"))
} else if len(c.alt) == 2 {
return option.Some(errors.New("Lalternative est pleine…"))
}
c.alt = append(c.alt, arg)
return
}
func (c *Cli) endAlt() (err option.Option[error]) {
if !c.needAlt || len(c.alt) != 2 {
return option.Some(errors.New("Lalternative nest pas pleine ou nest pas commencée…"))
}
r1, r2 := c.parse(c.alt[0]), c.parse(c.alt[1])
if me1, ok := r1.Ok(); ok {
if me2, ok := r2.Ok(); ok {
return c.c.If(me1, me2)
}
} else if e1, ok := r1.Err(); ok {
return option.Some(e1)
} else if e2, ok := r2.Err(); ok {
return option.Some(e2)
}
return
}
func (c *Cli) resetAlt() { c.needAlt, c.alt = false, c.alt[:0] }
func (c *Cli) resetMacro() { c.needMacro, c.macro = false, c.macro[:0] }
func (c *Cli) resetAll() {
c.resetAlt()
c.resetMacro()
c.c.Reset()
}
func (c *Cli) parse(arg string) option.Result[calc.MacroElement] {
var me calc.MacroElement
if arg == "[" {
me = calc.MacroCommand(cliToCalcFunc(c, beginMacro))
} else if regexp.MustCompile(`^\]\w+$`).MatchString(arg) {
me = calc.MacroCommand(cliToCalcFunc(c, storeMacro(arg[1:])))
} else if c.needMacro {
me = calc.MacroCommand(cliToCalcFunc(c, addMacro(arg)))
} else if arg == "?" {
me = calc.MacroCommand(cliToCalcFunc(c, conditional))
} else if c.needAlt {
me = calc.MacroCommand(cliToCalcFunc(c, addConditional(arg)))
} else if cb, exists := otherFunctions[arg]; exists {
me = calc.MacroCommand(otherToCalcFunc(cb))
} else if cb, exists := searchCalcFunction(arg); exists {
me = calc.MacroCommand(cb)
} else if cb, exists := searchCliFunction(arg); exists {
me = calc.MacroCommand(cliToCalcFunc(c, cb))
} else {
n, ok := number.Parse(arg).Get()
if !ok {
return option.Err[calc.MacroElement](fmt.Errorf("Commande inconnue: %s", arg))
}
me = calc.MacroNumber(n)
}
return option.Ok(me)
}
func (c *Cli) Exec(arg string) {
result := c.parse(arg)
if err, ok := result.Err(); ok {
printError(err)
c.resetAll()
return
}
if element, ok := result.Ok(); ok {
if n, ok := element.Left(); ok {
c.c.Push(n)
} else if cb, ok := element.Right(); ok {
if err, ok := cb(c.c).Get(); ok {
printError(err)
c.resetAll()
return
}
}
}
if c.needAlt && len(c.alt) == 2 {
if err, ok := c.endAlt().Get(); ok {
printError(err)
c.resetAll()
}
}
}
func (c *Cli) ExecAll(args string) {
for _, arg := range strings.Fields(args) {
c.Exec(arg)
}
}