123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- package eval
- import (
- "errors"
- "regexp"
- "strconv"
- "strings"
- "src.elv.sh/pkg/eval/vals"
- "src.elv.sh/pkg/wcwidth"
- )
- // String operations.
- // ErrInputOfEawkMustBeString is thrown when eawk gets a non-string input.
- var ErrInputOfEawkMustBeString = errors.New("input of eawk must be string")
- // TODO(xiaq): Document -override-wcswidth.
- func init() {
- addBuiltinFns(map[string]any{
- "<s": func(a, b string) bool { return a < b },
- "<=s": func(a, b string) bool { return a <= b },
- "==s": func(a, b string) bool { return a == b },
- "!=s": func(a, b string) bool { return a != b },
- ">s": func(a, b string) bool { return a > b },
- ">=s": func(a, b string) bool { return a >= b },
- "to-string": toString,
- "base": base,
- "wcswidth": wcwidth.Of,
- "-override-wcwidth": wcwidth.Override,
- "eawk": eawk,
- })
- }
- func toString(fm *Frame, args ...any) error {
- out := fm.ValueOutput()
- for _, a := range args {
- err := out.Put(vals.ToString(a))
- if err != nil {
- return err
- }
- }
- return nil
- }
- // ErrBadBase is thrown by the "base" builtin if the base is smaller than 2 or
- // greater than 36.
- var ErrBadBase = errors.New("bad base")
- func base(fm *Frame, b int, nums ...int) error {
- if b < 2 || b > 36 {
- return ErrBadBase
- }
- out := fm.ValueOutput()
- for _, num := range nums {
- err := out.Put(strconv.FormatInt(int64(num), b))
- if err != nil {
- return err
- }
- }
- return nil
- }
- var eawkWordSep = regexp.MustCompile("[ \t]+")
- func eawk(fm *Frame, f Callable, inputs Inputs) error {
- broken := false
- var err error
- inputs(func(v any) {
- if broken {
- return
- }
- line, ok := v.(string)
- if !ok {
- broken = true
- err = ErrInputOfEawkMustBeString
- return
- }
- args := []any{line}
- for _, field := range eawkWordSep.Split(strings.Trim(line, " \t"), -1) {
- args = append(args, field)
- }
- newFm := fm.Fork("fn of eawk")
- // TODO: Close port 0 of newFm.
- ex := f.Call(newFm, args, NoOpts)
- newFm.Close()
- if ex != nil {
- switch Reason(ex) {
- case nil, Continue:
- // nop
- case Break:
- broken = true
- default:
- broken = true
- err = ex
- }
- }
- })
- return err
- }
|