diff --git a/symbol-map.go b/symbol-map.go index 9ec6f22..848c112 100644 --- a/symbol-map.go +++ b/symbol-map.go @@ -182,21 +182,49 @@ func StringEndsWithOperator(s string) bool { return endingOperator(s) != SymNone } +// func endingOperator(s string) (sym Symbol) { +// var matchLength = 0 +// sym = SymNone +// lower := strings.TrimRight(strings.ToLower(s), " \t") +// for symbol, spec := range symbolMap { +// if strings.HasSuffix(lower, spec.repr) { +// if len(spec.repr) > matchLength { +// matchLength = len(spec.repr) +// if spec.kind == symClassOperator && (spec.opType == posInfix || spec.opType == posPrefix) { +// sym = symbol +// } else { +// sym = SymNone +// } +// } +// } +// } +// return +// } + func endingOperator(s string) (sym Symbol) { var matchLength = 0 + var repr string sym = SymNone lower := strings.TrimRight(strings.ToLower(s), " \t") for symbol, spec := range symbolMap { - if strings.HasSuffix(lower, spec.repr) { - if len(spec.repr) > matchLength { - matchLength = len(spec.repr) - if spec.kind == symClassOperator && (spec.opType == posInfix || spec.opType == posPrefix) { + if len(spec.repr) > matchLength || repr == spec.repr { + if strings.HasSuffix(lower, spec.repr) { + if isNotEndingSymbol(spec) && repr != spec.repr { + repr = spec.repr + matchLength = len(spec.repr) sym = symbol } else { sym = SymNone + break + // matchLength = 0 } } } } return } + +func isNotEndingSymbol(spec symbolSpec) bool { + return (spec.kind == symClassOperator && (spec.opType == posInfix || spec.opType == posPrefix)) || + (spec.kind == symClassParenthesis && spec.opType == posPrefix) +} diff --git a/t_symbol_test.go b/t_symbol_test.go new file mode 100644 index 0000000..4a75d96 --- /dev/null +++ b/t_symbol_test.go @@ -0,0 +1,58 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// t_symbol_test.go +package expr + +import ( + "testing" + + "git.portale-stac.it/go-pkg/expr/kern" +) + +func TestOperatorEnding(t *testing.T) { + section := "Symbol" + inputs := []inputType{ + /* 1 */ {`a++`, false, nil}, + /* 2 */ {`a;`, true, nil}, + /* 3 */ {`a +`, true, nil}, + /* 4 */ {`a + 1`, false, nil}, + /* 5 */ {`a - `, true, nil}, + /* 6 */ {`a( `, true, nil}, + /* 7 */ {`a) `, false, nil}, + /* 8 */ {`++a `, false, nil}, + } + + // testStringArrayEndingWithOperatorSpec(t, section, inputs, 6) + testStringArrayEndingWithOperator(t, section, inputs) +} + +func testStringEndingWithOperator(source string) bool { + return StringEndsWithOperator(source) +} + +func testStringArrayEndingWithOperatorSpec(t *testing.T, section string, inputs []inputType, spec ...int) { + for i := range spec { + if spec[i] < 1 || spec[i] > len(inputs) { + t.Errorf("Invalid test spec index: %d (must be between 1 and %d)", spec[i], len(inputs)) + continue + } + doEndingTest(t, section, inputs[spec[i]-1], spec[i]-1) + } +} + +func testStringArrayEndingWithOperator(t *testing.T, section string, inputs []inputType) { + for i, input := range inputs { + doEndingTest(t, section, input, i) + } +} + +func doEndingTest(t *testing.T, section string, input inputType, i int) { + wantErr := getWantedError(&input) + logTest(t, i+1, section, input.source, input.wantResult, wantErr) + gotResult := testStringEndingWithOperator(input.source) + t.Logf("Is %s op ending? %v", input.source, gotResult) + if gotResult != input.wantResult.(bool) { + t.Errorf("%d: `%s` -> result = %v [%s], want = %v [%s]", i+1, input.source, gotResult, kern.TypeName(gotResult), input.wantResult, kern.TypeName(input.wantResult)) + } +}