Formatter option is now composed of two data: flags (lower 16 bits) and indentation size (higher 16 bits).

DictType and ListType formatter use both indent and flag options.
Simple-store now makes a DictType from its data and its ToString() function returns dict.ToString()
This commit is contained in:
Celestino Amoroso 2024-06-11 16:32:01 +02:00
parent 56d6d06d15
commit 9fb611aa20
8 changed files with 126 additions and 42 deletions

View File

@ -32,42 +32,52 @@ func newDict(dictAny map[any]*term) (dict *DictType) {
return return
} }
func (dict *DictType) toMultiLine(sb *strings.Builder, indent int) { func (dict *DictType) toMultiLine(sb *strings.Builder, opt FmtOpt) {
sb.WriteString(strings.Repeat("\t", indent)) indent := GetFormatIndent(opt)
sb.WriteString("{\n") flags := GetFormatFlags(opt)
//sb.WriteString(strings.Repeat(" ", indent))
sb.WriteByte('{')
first := true if len(*dict) > 0 {
for name, value := range *dict { innerOpt := MakeFormatOptions(flags, indent+1)
if first { nest := strings.Repeat(" ", indent+1)
first = false sb.WriteByte('\n')
} else {
sb.WriteByte(',')
sb.WriteByte('\n')
}
sb.WriteString(strings.Repeat("\t", indent+1)) first := true
if key, ok := name.(string); ok { for name, value := range *dict {
sb.WriteString(string('"') + key + string('"')) if first {
} else { first = false
sb.WriteString(fmt.Sprintf("%v", name)) } else {
} sb.WriteByte(',')
sb.WriteString(": ") sb.WriteByte('\n')
if f, ok := value.(Formatter); ok { }
sb.WriteString(f.ToString(MultiLine))
} else if _, ok = value.(Functor); ok { sb.WriteString(nest)
sb.WriteString("func(){}") if key, ok := name.(string); ok {
} else { sb.WriteString(string('"') + key + string('"'))
sb.WriteString(fmt.Sprintf("%v", value)) } else {
sb.WriteString(fmt.Sprintf("%v", name))
}
sb.WriteString(": ")
if f, ok := value.(Formatter); ok {
sb.WriteString(f.ToString(innerOpt))
} else if _, ok = value.(Functor); ok {
sb.WriteString("func(){}")
} else {
sb.WriteString(fmt.Sprintf("%v", value))
}
} }
sb.WriteByte('\n')
sb.WriteString(strings.Repeat(" ", indent))
} }
sb.WriteString(strings.Repeat("\t", indent)) sb.WriteString("}")
sb.WriteString("\n}")
} }
func (dict *DictType) ToString(opt FmtOpt) string { func (dict *DictType) ToString(opt FmtOpt) string {
var sb strings.Builder var sb strings.Builder
if opt&MultiLine != 0 { flags := GetFormatFlags(opt)
dict.toMultiLine(&sb, 0) if flags&MultiLine != 0 {
dict.toMultiLine(&sb, opt)
} else { } else {
sb.WriteByte('{') sb.WriteByte('{')
first := true first := true
@ -133,3 +143,9 @@ func (dict *DictType) setItem(key any, value any) (err error) {
(*dict)[key] = value (*dict)[key] = value
return return
} }
////////////////
type DictFormat interface {
ToDict() *DictType
}

View File

@ -6,7 +6,7 @@ package expr
import "fmt" import "fmt"
type FmtOpt uint16 type FmtOpt uint32 // lower 16 bits hold a bit-mask, higher 16 bits hold an indentation number
const ( const (
TTY FmtOpt = 1 << iota TTY FmtOpt = 1 << iota
@ -30,6 +30,18 @@ func TruncateString(s string) (trunc string) {
return return
} }
func MakeFormatOptions(flags FmtOpt, indent int) FmtOpt {
return FmtOpt(indent<<16) | flags
}
func GetFormatFlags(opt FmtOpt) FmtOpt {
return opt & 0xFFFF
}
func GetFormatIndent(opt FmtOpt) int {
return int(opt >> 16)
}
type Formatter interface { type Formatter interface {
ToString(options FmtOpt) string ToString(options FmtOpt) string
} }

View File

@ -21,7 +21,7 @@ func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
if functor.info != nil { if functor.info != nil {
s = functor.info.ToString(opt) s = functor.info.ToString(opt)
} else { } else {
s = "func() {<body>}" s = "func() {}"
} }
return s return s
} }
@ -180,7 +180,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
} else { } else {
sb.WriteString(TypeAny) sb.WriteString(TypeAny)
} }
sb.WriteString(" {<body>}") sb.WriteString(" {}")
return sb.String() return sb.String()
} }

View File

@ -52,16 +52,24 @@ func ListFromStrings(stringList []string) (list *ListType) {
} }
func (ls *ListType) ToString(opt FmtOpt) (s string) { func (ls *ListType) ToString(opt FmtOpt) (s string) {
indent := GetFormatIndent(opt)
flags := GetFormatFlags(opt)
var sb strings.Builder var sb strings.Builder
sb.WriteByte('[') sb.WriteByte('[')
if len(*ls) > 0 { if len(*ls) > 0 {
if opt&MultiLine != 0 { innerOpt := MakeFormatOptions(flags, indent+1)
sb.WriteString("\n ") nest := strings.Repeat(" ", indent+1)
if flags&MultiLine != 0 {
sb.WriteByte('\n')
sb.WriteString(nest)
} }
for i, item := range []any(*ls) { for i, item := range []any(*ls) {
if i > 0 { if i > 0 {
if opt&MultiLine != 0 { if flags&MultiLine != 0 {
sb.WriteString(",\n ") sb.WriteString(",\n")
sb.WriteString(nest)
} else { } else {
sb.WriteString(", ") sb.WriteString(", ")
} }
@ -70,17 +78,20 @@ func (ls *ListType) ToString(opt FmtOpt) (s string) {
sb.WriteByte('"') sb.WriteByte('"')
sb.WriteString(s) sb.WriteString(s)
sb.WriteByte('"') sb.WriteByte('"')
} else if formatter, ok := item.(Formatter); ok {
sb.WriteString(formatter.ToString(innerOpt))
} else { } else {
sb.WriteString(fmt.Sprintf("%v", item)) sb.WriteString(fmt.Sprintf("%v", item))
} }
} }
if opt&MultiLine != 0 { if flags&MultiLine != 0 {
sb.WriteByte('\n') sb.WriteByte('\n')
sb.WriteString(strings.Repeat(" ", indent))
} }
} }
sb.WriteByte(']') sb.WriteByte(']')
s = sb.String() s = sb.String()
if opt&Truncate != 0 && len(s) > TruncateSize { if flags&Truncate != 0 && len(s) > TruncateSize {
s = TruncateString(s) s = TruncateString(s)
} }
return return

View File

@ -31,7 +31,9 @@ func evalContextValue(ctx ExprContext, self *term) (v any, err error) {
} }
if sourceCtx != nil { if sourceCtx != nil {
if formatter, ok := sourceCtx.(Formatter); ok { if formatter, ok := sourceCtx.(DictFormat); ok {
v = formatter.ToDict()
} else if formatter, ok := sourceCtx.(Formatter); ok {
v = formatter.ToString(0) v = formatter.ToString(0)
} else { } else {
// keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' }) // keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })

View File

@ -7,7 +7,7 @@ package expr
import ( import (
"fmt" "fmt"
"slices" "slices"
"strings" // "strings"
) )
type SimpleStore struct { type SimpleStore struct {
@ -50,7 +50,7 @@ func (ctx *SimpleStore) Merge(src ExprContext) {
ctx.funcStore[name], _ = src.GetFuncInfo(name) ctx.funcStore[name], _ = src.GetFuncInfo(name)
} }
} }
/*
func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) { func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
sb.WriteString("vars: {\n") sb.WriteString("vars: {\n")
first := true first := true
@ -116,6 +116,49 @@ func (ctx *SimpleStore) ToString(opt FmtOpt) string {
funcsCtxToBuilder(&sb, ctx, 0) funcsCtxToBuilder(&sb, ctx, 0)
return sb.String() return sb.String()
} }
*/
func (ctx *SimpleStore) ToString(opt FmtOpt) string {
dict := ctx.ToDict()
return dict.ToString(opt)
}
func (ctx *SimpleStore) varsToDict(dict *DictType) *DictType {
names := ctx.EnumVars(nil)
slices.Sort(names)
for _, name := range ctx.EnumVars(nil) {
value, _ := ctx.GetVar(name)
if f, ok := value.(Formatter); ok {
(*dict)[name] = f.ToString(0)
} else if _, ok = value.(Functor); ok {
(*dict)[name] = "func(){}"
} else {
(*dict)[name] = fmt.Sprintf("%v", value)
}
}
return dict
}
func (ctx *SimpleStore) funcsToDict(dict *DictType) *DictType {
names := ctx.EnumFuncs(func(name string) bool { return true })
slices.Sort(names)
for _, name := range names {
value, _ := ctx.GetFuncInfo(name)
if formatter, ok := value.(Formatter); ok {
(*dict)[name] = formatter.ToString(0)
} else {
(*dict)[name] = fmt.Sprintf("%v", value)
}
}
return dict
}
func (ctx *SimpleStore) ToDict() (dict *DictType) {
dict = MakeDict()
(*dict)["variables"] = ctx.varsToDict(MakeDict())
(*dict)["functions"] = ctx.funcsToDict(MakeDict())
return
}
func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) { func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) {
v, exists = ctx.varStore[varName] v, exists = ctx.varStore[varName]

View File

@ -110,7 +110,7 @@ func TestDictToStringMultiLine(t *testing.T) {
var good bool var good bool
section := "dict-ToString-ML" section := "dict-ToString-ML"
want := `{ want := `{
"first": 1 "first": 1
}` }`
args := map[any]*term{ args := map[any]*term{
"first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)), "first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)),

View File

@ -44,7 +44,7 @@ func dummy(ctx ExprContext, name string, args []any) (result any, err error) {
func TestFunctionToStringSimple(t *testing.T) { func TestFunctionToStringSimple(t *testing.T) {
source := NewGolangFunctor(dummy) source := NewGolangFunctor(dummy)
want := "func() {<body>}" want := "func() {}"
got := source.ToString(0) got := source.ToString(0)
if got != want { if got != want {
t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want) t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want)