// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // Symbol.go package scan import ( "strings" ) var symbolMap map[Symbol]symbolSpec type SymbolClass int16 const ( SymClassOperator SymbolClass = iota SymClassCommand SymClassIdentifier SymClassDelimiter SymClassParenthesis SymClassDeclaration SymClassValue SymClassOther ) type symbolSpec struct { repr string kind SymbolClass opType TermPosition } func init() { symbolMap = map[Symbol]symbolSpec{ SymUnknown: {"", SymClassOther, PosLeaf}, // -1: Unknown symbol SymNone: {"", SymClassOther, PosLeaf}, // 0: Null value for variable of type symbol SymError: {"", SymClassOther, PosLeaf}, // 1: Error reading from stream SymEos: {"", SymClassOther, PosLeaf}, // 2: End of stream SymMinus: {"-", SymClassOperator, PosInfix}, // 3: '-' SymMinusEqual: {"-=", SymClassOperator, PosInfix}, // 4: '-=' SymDoubleMinus: {"--", SymClassOperator, PosPostfix}, // 5: '--' SymPlus: {"+", SymClassOperator, PosInfix}, // 6: '+' SymPlusEqual: {"+=", SymClassOperator, PosInfix}, // 7: '+=' SymDoublePlus: {"++", SymClassOperator, PosPostfix}, // 8: '++' SymStar: {"*", SymClassOperator, PosInfix}, // 9: '*' SymDoubleStar: {"**", SymClassOperator, PosInfix}, // 10: '**' SymSlash: {"/", SymClassOperator, PosInfix}, // 11: '/' SymBackSlash: {"\\", SymClassOperator, PosLeaf}, // 12: '\' SymVertBar: {"|", SymClassOperator, PosInfix}, // 13: '|' SymDoubleVertBar: {"||", SymClassOperator, PosInfix}, // 14: '||' SymComma: {",", SymClassOperator, PosInfix}, // 15: ',' SymColon: {":", SymClassOperator, PosInfix}, // 16: ':' SymSemiColon: {";", SymClassOperator, PosInfix}, // 17: ';' SymDot: {".", SymClassOperator, PosInfix}, // 18: '.' SymDotSlash: {"./", SymClassOperator, PosInfix}, // 19: './' SymQuote: {"'", SymClassDelimiter, PosLeaf}, // 20: '\'' SymDoubleQuote: {"\"", SymClassDelimiter, PosLeaf}, // 21: '"' SymBackTick: {"`", SymClassDelimiter, PosLeaf}, // 22: '`' SymExclamation: {"!", SymClassOperator, PosPostfix}, // 23: '!' SymQuestion: {"?", SymClassOperator, PosInfix}, // 24: '?' SymAmpersand: {"&", SymClassOperator, PosInfix}, // 25: '&' SymDoubleAmpersand: {"&&", SymClassOperator, PosInfix}, // 26: '&&' SymPercent: {"%", SymClassOperator, PosInfix}, // 27: '%' SymAt: {"@", SymClassOperator, PosPrefix}, // 28: '@' SymUndescore: {"_", SymClassIdentifier, PosLeaf}, // 29: '_' SymEqual: {"=", SymClassOperator, PosInfix}, // 30: '=' SymDoubleEqual: {"==", SymClassOperator, PosInfix}, // 31: '==' SymLess: {"<", SymClassOperator, PosInfix}, // 32: '<' SymLessOrEqual: {"<=", SymClassOperator, PosInfix}, // 33: '<=' SymGreater: {">", SymClassOperator, PosInfix}, // 34: '>' SymGreaterOrEqual: {">=", SymClassOperator, PosInfix}, // 35: '>=' SymLessGreater: {"<>", SymClassOperator, PosInfix}, // 36: '<>' SymNotEqual: {"!=", SymClassOperator, PosInfix}, // 37: '!=' SymDollar: {"$", SymClassOperator, PosPrefix}, // 38: '$' SymHash: {"#", SymClassOperator, PosPrefix}, // 39: '#' SymOpenRound: {"(", SymClassParenthesis, PosPrefix}, // 40: '(' SymClosedRound: {")", SymClassParenthesis, PosPostfix}, // 41: ')' SymOpenSquare: {"[", SymClassParenthesis, PosPrefix}, // 42: '[' SymClosedSquare: {"]", SymClassParenthesis, PosPostfix}, // 43: ']' SymOpenBrace: {"{", SymClassParenthesis, PosPrefix}, // 44: '{' SymClosedBrace: {"}", SymClassParenthesis, PosPostfix}, // 45: '}' SymTilde: {"~", SymClassOperator, PosPrefix}, // 46: '~' SymDoubleQuestion: {"??", SymClassOperator, PosInfix}, // 47: '??' SymQuestionEqual: {"?=", SymClassOperator, PosInfix}, // 48: '?=' SymQuestionExclam: {"?!", SymClassOperator, PosInfix}, // 49: '?!' SymDoubleAt: {"@@", SymClassCommand, PosLeaf}, // 50: '@@' SymDoubleColon: {"::", SymClassOperator, PosInfix}, // 51: '::' SymDoubleGreater: {">>", SymClassOperator, PosInfix}, // 52: '>>' SymDoubleLess: {"<<", SymClassOperator, PosInfix}, // 53: '<<' SymCaret: {"^", SymClassOperator, PosInfix}, // 54: '^' SymDollarRound: {"$(", SymClassOperator, PosPrefix}, // 55: '$(' SymOpenClosedRound: {"()", SymClassOperator, PosPostfix}, // 56: '()' SymDoubleDollar: {"$$", SymClassCommand, PosLeaf}, // 57: '$$' SymDoubleDot: {"..", SymClassOperator, PosInfix}, // 58: '..' SymTripleDot: {"...", SymClassOperator, PosPostfix}, // 59: '...' SymStarEqual: {"*=", SymClassOperator, PosInfix}, // 60: '*=' SymSlashEqual: {"/=", SymClassOperator, PosInfix}, // 61: '/=' SymPercEqual: {"%=", SymClassOperator, PosInfix}, // 62: '%=' SymDoubleLessEqual: {"<<=", SymClassOperator, PosInfix}, // 63: '<<=' SymDoubleGreaterEqual: {">>=", SymClassOperator, PosInfix}, // 64: '>>=' SymAmpersandEqual: {"&=", SymClassOperator, PosInfix}, // 65: '&=' SymVertBarEqual: {"|=", SymClassOperator, PosInfix}, // 65: '|=' SymCaretEqual: {"^=", SymClassOperator, PosInfix}, // 66: '^=' SymPlusGreater: {"+>", SymClassOperator, PosInfix}, // 67: '+>' SymLessPlus: {"<+", SymClassOperator, PosInfix}, // 68: '<+' SymPreInc: {"++", SymClassOperator, PosPrefix}, // : '++' SymPreDec: {"--", SymClassOperator, PosPrefix}, // : '--' // SymChangeSign // SymUnchangeSign // SymIdentifier // SymBool // SymInteger // SymVariable // SymFloat // SymFraction // SymString // SymIterator // SymOr: "or", // SymAnd: "and", // SymNot: "not", // SymComment // SymFuncCall // SymFuncDef // SymList // SymDict // SymIndex // SymExpression // SymSelector // ::= "?" {":" } ["::" ] // SymSelectorCase // ::= [] "{" "}" // // SymOpenComment // 0: '/*' // // SymClosedComment // 0: '*/' // // SymOneLineComment // 0: '//' // keywordBase SymKwAnd: {"and", SymClassOperator, PosInfix}, SymKwNot: {"not", SymClassOperator, PosInfix}, SymKwOr: {"or", SymClassOperator, PosInfix}, SymKwBut: {"but", SymClassOperator, PosInfix}, SymKwMap: {"map", SymClassOperator, PosInfix}, SymKwFilter: {"filter", SymClassOperator, PosInfix}, SymKwDigest: {"digest", SymClassOperator, PosInfix}, SymKwCat: {"cat", SymClassOperator, PosInfix}, SymKwJoin: {"join", SymClassOperator, PosInfix}, SymKwGroupBy: {"groupby", SymClassOperator, PosInfix}, SymKwFunc: {"func(", SymClassDeclaration, PosPrefix}, SymKwBuiltin: {"builtin", SymClassOperator, PosPrefix}, SymKwPlugin: {"plugin", SymClassOperator, PosPrefix}, SymKwIn: {"in", SymClassOperator, PosInfix}, SymKwInclude: {"include", SymClassOperator, PosPrefix}, SymKwNil: {"nil", SymClassValue, PosLeaf}, SymKwUnset: {"unset", SymClassOperator, PosPrefix}, } } func SymToString(sym Symbol) string { if s, ok := symbolMap[sym]; ok { return s.repr } return "" } func SymListToString(symList []Symbol, quote bool) string { var sb strings.Builder if len(symList) == 0 { sb.WriteString("") } else { for _, sym := range symList { if sb.Len() > 0 { sb.WriteByte(',') sb.WriteByte(' ') } if quote { sb.WriteByte('`') } sb.WriteString(SymToString(sym)) if quote { sb.WriteByte('`') } } } return sb.String() } 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 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) }