Filter: Apply lint suggestions

This commit is contained in:
Palapeli 2026-04-06 07:06:18 -04:00
parent 32e7c6a3f8
commit a700af444e
No known key found for this signature in database
GPG Key ID: 1FFE8F556A474925
7 changed files with 293 additions and 315 deletions

View File

@ -23,80 +23,80 @@ func Eval(basenode *TreeNode, context map[string]string, queryGame string) (valu
}
}()
this := &expression{basenode, context, queryGame}
return this.eval(basenode), nil
e := &expression{basenode, context, queryGame}
return e.eval(basenode), nil
}
func (this *expression) eval(basenode *TreeNode) int64 {
func (e *expression) eval(basenode *TreeNode) int64 {
for _, node := range basenode.items {
switch node.Value.Category() {
case CatFunction:
return this.switchFunction(node)
return e.switchFunction(node)
case CatValue:
return this.getNumber(node)
return e.getNumber(node)
case CatOther:
return this.switchOther(node)
return e.switchOther(node)
}
}
panic("eval failed")
}
func (this *expression) switchOther(node *TreeNode) int64 {
func (e *expression) switchOther(node *TreeNode) int64 {
switch v1 := node.Value.(type) {
case *GroupToken:
if v1.GroupType == "()" {
return this.eval(node)
return e.eval(node)
}
}
panic("invalid node " + node.String())
}
func (this *expression) switchFunction(node *TreeNode) int64 {
func (e *expression) switchFunction(node *TreeNode) int64 {
val1 := node.Value.(*OperatorToken)
switch strings.ToLower(val1.Operator) {
case "=":
return this.evalEquals(node.Items())
return e.evalEquals(node.Items())
case "==":
return this.evalEquals(node.Items())
return e.evalEquals(node.Items())
case "!=":
return this.evalNotEquals(node.Items())
return e.evalNotEquals(node.Items())
case ">":
return this.evalMathOperator(this.evalMathGreater, node.Items())
return e.evalMathOperator(e.evalMathGreater, node.Items())
case "<":
return this.evalMathOperator(this.evalMathLess, node.Items())
return e.evalMathOperator(e.evalMathLess, node.Items())
case ">=":
return this.evalMathOperator(this.evalMathGreaterOrEqual, node.Items())
return e.evalMathOperator(e.evalMathGreaterOrEqual, node.Items())
case "<=":
return this.evalMathOperator(this.evalMathLessOrEqual, node.Items())
return e.evalMathOperator(e.evalMathLessOrEqual, node.Items())
case "+":
return this.evalMathOperator(this.evalMathPlus, node.Items())
return e.evalMathOperator(e.evalMathPlus, node.Items())
case "-":
return this.evalMathOperator(this.evalMathMinus, node.Items())
return e.evalMathOperator(e.evalMathMinus, node.Items())
case "&":
return this.evalMathOperator(this.evalMathAnd, node.Items())
return e.evalMathOperator(e.evalMathAnd, node.Items())
case "|":
return this.evalMathOperator(this.evalMathOr, node.Items())
return e.evalMathOperator(e.evalMathOr, node.Items())
case "^":
return this.evalMathOperator(this.evalMathXor, node.Items())
return e.evalMathOperator(e.evalMathXor, node.Items())
case "<<":
return this.evalMathOperator(this.evalMathLShift, node.Items())
return e.evalMathOperator(e.evalMathLShift, node.Items())
case ">>":
return this.evalMathOperator(this.evalMathRShift, node.Items())
return e.evalMathOperator(e.evalMathRShift, node.Items())
case "and":
return this.evalAnd(node.Items())
return e.evalAnd(node.Items())
case "or":
return this.evalOr(node.Items())
return e.evalOr(node.Items())
case "&&":
return this.evalAnd(node.Items())
return e.evalAnd(node.Items())
case "||":
return this.evalOr(node.Items())
return e.evalOr(node.Items())
case "like":
return this.evalLike(node.Items())
return e.evalLike(node.Items())
default:
panic("function not supported: " + val1.Operator)
@ -104,17 +104,17 @@ func (this *expression) switchFunction(node *TreeNode) int64 {
}
func (this *expression) getString(node *TreeNode) string {
func (e *expression) getString(node *TreeNode) string {
switch v := node.Value.(type) {
case *NumberToken:
return strconv.FormatInt(v.Value, 10)
case *IdentityToken:
return this.getValue(v)
return e.getValue(v)
case *OperatorToken:
return strconv.FormatInt(this.switchFunction(node), 10)
return strconv.FormatInt(e.switchFunction(node), 10)
case *GroupToken:
if v.GroupType == "()" {
return strconv.FormatInt(this.eval(node), 10)
return strconv.FormatInt(e.eval(node), 10)
}
panic("unexpected grouping type: " + node.String())
case *TextToken:
@ -125,26 +125,26 @@ func (this *expression) getString(node *TreeNode) string {
}
}
func (this *expression) evalEquals(args []*TreeNode) int64 {
func (e *expression) evalEquals(args []*TreeNode) int64 {
cnt := len(args)
switch {
case cnt < 2:
panic("operator missing arguments")
case cnt == 2:
if n, ok := args[0].Value.(*IdentityToken); ok {
if n.Name == "rk" && this.queryGame == "mariokartwii" {
return this.evalEqualsRK(this.getString(args[1]))
if n.Name == "rk" && e.queryGame == "mariokartwii" {
return e.evalEqualsRK(e.getString(args[1]))
}
}
if this.getString(args[0]) == this.getString(args[1]) {
if e.getString(args[0]) == e.getString(args[1]) {
return 1
}
return 0
default:
arg := this.getString(args[0])
arg := e.getString(args[0])
for i := 1; i < cnt; i++ {
if arg != this.getString(args[i]) {
if arg != e.getString(args[i]) {
return 0
}
}
@ -153,8 +153,8 @@ func (this *expression) evalEquals(args []*TreeNode) int64 {
}
// Operator override
func (this *expression) evalEqualsRK(value string) int64 {
rk := this.context["rk"]
func (e *expression) evalEqualsRK(value string) int64 {
rk := e.context["rk"]
// Check and remove regional searches due to the limited player count
// China (ID 6) gets a pass because it was never released
if len(rk) == 4 && (strings.HasPrefix(rk, "vs_") || strings.HasPrefix(rk, "bt_")) && rk[3] >= '0' && rk[3] < '6' {
@ -171,20 +171,20 @@ func (this *expression) evalEqualsRK(value string) int64 {
return 0
}
func (this *expression) evalNotEquals(args []*TreeNode) int64 {
func (e *expression) evalNotEquals(args []*TreeNode) int64 {
cnt := len(args)
switch {
case cnt < 2:
panic("operator missing arguments")
case cnt == 2:
if this.getString(args[0]) != this.getString(args[1]) {
if e.getString(args[0]) != e.getString(args[1]) {
return 1
}
return 0
default:
arg := this.getString(args[0])
arg := e.getString(args[0])
for i := 1; i < cnt; i++ {
if arg == this.getString(args[i]) {
if arg == e.getString(args[i]) {
return 0
}
}
@ -192,57 +192,57 @@ func (this *expression) evalNotEquals(args []*TreeNode) int64 {
}
}
func (this *expression) evalAnd(args []*TreeNode) int64 {
func (e *expression) evalAnd(args []*TreeNode) int64 {
cnt := len(args)
if cnt < 2 {
panic("operator missing arguments")
}
for i := 0; i < cnt; i++ {
if this.getString(args[i]) == "0" {
if e.getString(args[i]) == "0" {
return 0
}
}
return 1
}
func (this *expression) evalOr(args []*TreeNode) int64 {
func (e *expression) evalOr(args []*TreeNode) int64 {
cnt := len(args)
if cnt < 2 {
panic("operator missing arguments")
}
for i := 0; i < cnt; i++ {
if this.getString(args[i]) != "0" {
if e.getString(args[i]) != "0" {
return 1
}
}
return 0
}
func (this *expression) getNumber(node *TreeNode) int64 {
func (e *expression) getNumber(node *TreeNode) int64 {
switch v := node.Value.(type) {
case *NumberToken:
return v.Value
case *IdentityToken:
r1 := this.getValue(v)
return this.toInt64(r1)
r1 := e.getValue(v)
return e.toInt64(r1)
case *OperatorToken:
return this.switchFunction(node)
return e.switchFunction(node)
case *GroupToken:
if v.GroupType == "()" {
return this.eval(node)
return e.eval(node)
}
panic("unexpected grouping type: " + node.String())
case *TextToken:
return this.toInt64(node.Value.(*TextToken).Text)
return e.toInt64(node.Value.(*TextToken).Text)
default:
panic("unexpected value: " + node.String())
}
}
func (this *expression) evalMathOperator(fn func(int64, int64) int64, args []*TreeNode) int64 {
func (e *expression) evalMathOperator(fn func(int64, int64) int64, args []*TreeNode) int64 {
cnt := len(args)
switch {
case cnt < 2:
@ -250,101 +250,101 @@ func (this *expression) evalMathOperator(fn func(int64, int64) int64, args []*Tr
case cnt == 2:
if n, ok := args[0].Value.(*IdentityToken); ok {
// Remove VR search due to the limited player count
if (n.Name == "ev" || n.Name == "eb") && this.queryGame == "mariokartwii" {
if (n.Name == "ev" || n.Name == "eb") && e.queryGame == "mariokartwii" {
return 1
}
}
return fn(this.getNumber(args[0]), this.getNumber(args[1]))
return fn(e.getNumber(args[0]), e.getNumber(args[1]))
default:
answ := fn(this.getNumber(args[0]), this.getNumber(args[1]))
answ := fn(e.getNumber(args[0]), e.getNumber(args[1]))
for i := 2; i < cnt; i++ {
answ = fn(answ, this.getNumber(args[i]))
answ = fn(answ, e.getNumber(args[i]))
}
return answ
}
}
func (this *expression) evalMathPlus(val1, val2 int64) int64 {
func (e *expression) evalMathPlus(val1, val2 int64) int64 {
return val1 + val2
}
func (this *expression) evalMathMinus(val1, val2 int64) int64 {
func (e *expression) evalMathMinus(val1, val2 int64) int64 {
return val1 - val2
}
func (this *expression) evalMathGreater(val1, val2 int64) int64 {
func (e *expression) evalMathGreater(val1, val2 int64) int64 {
if val1 > val2 {
return 1
}
return 0
}
func (this *expression) evalMathLess(val1, val2 int64) int64 {
func (e *expression) evalMathLess(val1, val2 int64) int64 {
if val1 < val2 {
return 1
}
return 0
}
func (this *expression) evalMathGreaterOrEqual(val1, val2 int64) int64 {
func (e *expression) evalMathGreaterOrEqual(val1, val2 int64) int64 {
if val1 >= val2 {
return 1
}
return 0
}
func (this *expression) evalMathLessOrEqual(val1, val2 int64) int64 {
func (e *expression) evalMathLessOrEqual(val1, val2 int64) int64 {
if val1 <= val2 {
return 1
}
return 0
}
func (this *expression) evalMathAnd(val1, val2 int64) int64 {
func (e *expression) evalMathAnd(val1, val2 int64) int64 {
return val1 & val2
}
func (this *expression) evalMathOr(val1, val2 int64) int64 {
func (e *expression) evalMathOr(val1, val2 int64) int64 {
return val1 | val2
}
func (this *expression) evalMathXor(val1, val2 int64) int64 {
func (e *expression) evalMathXor(val1, val2 int64) int64 {
return val1 ^ val2
}
func (this *expression) evalMathLShift(val1, val2 int64) int64 {
func (e *expression) evalMathLShift(val1, val2 int64) int64 {
return val1 << val2
}
func (this *expression) evalMathRShift(val1, val2 int64) int64 {
func (e *expression) evalMathRShift(val1, val2 int64) int64 {
return val1 >> val2
}
func (this *expression) evalLike(args []*TreeNode) int64 {
func (e *expression) evalLike(args []*TreeNode) int64 {
cnt := len(args)
switch {
case cnt < 2:
panic("operator missing arguments")
case cnt == 2:
return this.evalLikeSingle(args[0], args[1])
return e.evalLikeSingle(args[0], args[1])
default:
panic("operator like does not support multiple arguments")
panic("operator LIKE does not support multiple arguments")
}
}
func (this *expression) evalLikeSingle(arg1, arg2 *TreeNode) int64 {
val1 := this.getString(arg1)
val2 := this.getString(arg2)
func (e *expression) evalLikeSingle(arg1, arg2 *TreeNode) int64 {
val1 := e.getString(arg1)
val2 := e.getString(arg2)
allowedCharacters := `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_%\`
regexString := "^"
// Convert SQL like pattern to regex
// Convert SQL LIKE pattern to regex
for i, c := range val2 {
if strings.IndexRune(allowedCharacters, c) < 0 {
panic("invalid character in like pattern: " + string(c))
if !strings.ContainsRune(allowedCharacters, c) {
panic("invalid character in LIKE pattern: " + string(c))
}
if i != 0 && val2[i-1] == '\\' {
@ -384,11 +384,11 @@ func (this *expression) evalLikeSingle(arg1, arg2 *TreeNode) int64 {
}
// Get a value from the context.
func (this *expression) getValue(token *IdentityToken) string {
return this.context[token.Name]
func (e *expression) getValue(token *IdentityToken) string {
return e.context[token.Name]
}
func (this *expression) toInt64(value string) int64 {
func (e *expression) toInt64(value string) int64 {
val, err := strconv.ParseInt(value, 10, 64)
if err != nil {
panic(err)

View File

@ -33,73 +33,68 @@ func Parse(input string) (root *TreeNode, err error) {
return root, err
}
func (this *parser) getCurr() Token {
if this.curr != nil {
return this.curr.Value
func (p *parser) getCurr() Token {
if p.curr != nil {
return p.curr.Value
}
return nil
}
func (this *parser) parse() {
this.pumpExpression()
func (p *parser) parse() {
p.pumpExpression()
}
func (this *parser) add(token Token) *TreeNode {
return this.curr.Add(token)
func (p *parser) add(token Token) *TreeNode {
return p.curr.Add(token)
}
func (this *parser) push(token Token) *TreeNode {
return this.curr.Push(token)
func (p *parser) push(token Token) *TreeNode {
return p.curr.Push(token)
}
func (this *parser) lastNode() *TreeNode {
return this.curr.LastElement()
func (p *parser) lastNode() *TreeNode {
return p.curr.LastElement()
}
func (this *parser) parentNode() *TreeNode {
return this.curr.Parent()
}
func (this *parser) commit() string {
return this.scan.Commit()
func (p *parser) commit() string {
return p.scan.Commit()
}
// parseOpenBracket
func (this *parser) parseOpenBracket() bool {
this.curr = this.add(NewGroupToken("()"))
this.commit()
func (p *parser) parseOpenBracket() bool {
p.curr = p.add(NewGroupToken("()"))
p.commit()
return true
}
// parseCloseBracket
func (this *parser) parseCloseBracket() stateFn {
func (p *parser) parseCloseBracket() stateFn {
for {
v1, ok := this.curr.Value.(*GroupToken)
v1, ok := p.curr.Value.(*GroupToken)
if ok && v1.GroupType == "()" {
this.commit()
this.curr = this.curr.Parent()
p.commit()
p.curr = p.curr.Parent()
return branchExpressionOperatorPart
}
if ok && v1.GroupType == "" {
//must be a bracket part of a parent loop, exit this sub loop.
this.scan.Backup()
p.scan.Backup()
return nil
}
if this.curr.Parent() == nil {
if p.curr.Parent() == nil {
panic("brackets not closed")
}
this.curr = this.curr.Parent()
p.curr = p.curr.Parent()
}
panic("unreachable code")
}
func (this *parser) AcceptOperator() bool {
scan := this.scan
func (p *parser) AcceptOperator() bool {
scan := p.scan
state := scan.SaveState()
for _, op := range operatorList {
if scan.Prefix(op) || scan.Prefix(strings.ToUpper(op)) {
p := scan.Peek()
if unicode.IsLetter(rune(op[0])) && (unicode.IsLetter(p) || unicode.IsNumber(p) || strings.IndexRune(charValidString, p) >= 0) {
if unicode.IsLetter(rune(op[0])) && (unicode.IsLetter(p) || unicode.IsNumber(p) || strings.ContainsRune(charValidString, p)) {
// this is a prefix of a longer word
scan.LoadState(state)
continue
@ -111,10 +106,10 @@ func (this *parser) AcceptOperator() bool {
}
// parseOperator
func (this *parser) parseOperator() bool {
operator := this.commit()
lastnode := this.lastNode()
onode, ok := this.getCurr().(*OperatorToken)
func (p *parser) parseOperator() bool {
operator := p.commit()
lastnode := p.lastNode()
onode, ok := p.getCurr().(*OperatorToken)
//push excisting operator up in tree structure
if ok {
//operator is the same current operator ignore
@ -125,51 +120,51 @@ func (this *parser) parseOperator() bool {
//fmt.Println(onode, operator, onode.Precedence(operator))
if onode.Precedence(operator) > 0 {
if lastnode != nil {
this.curr = lastnode.Push(NewOperatorToken(operator))
p.curr = lastnode.Push(NewOperatorToken(operator))
return true
}
}
//after */ presedence fallback and continue pushing +- operators from the bottom.
if onode.Precedence(operator) < 0 {
for {
v1, ok := this.curr.Parent().Value.(*OperatorToken)
v1, ok := p.curr.Parent().Value.(*OperatorToken)
//if ok && strings.Index("+-", v1.Name) >= 0 {
if ok && operators.Level(v1.Operator) >= 0 {
this.curr = this.curr.Parent()
p.curr = p.curr.Parent()
} else {
break
}
}
}
//standard operator push
this.curr = this.push(NewOperatorToken(operator))
p.curr = p.push(NewOperatorToken(operator))
return true
}
//set previous found value as argument of the operator
if lastnode != nil {
this.curr = lastnode.Push(NewOperatorToken(operator))
p.curr = lastnode.Push(NewOperatorToken(operator))
} else {
this.state = nil
p.state = nil
panic(fmt.Sprintf("expecting a value before operator %q", operator))
}
return true
}
// parseLRFunc
func (this *parser) parseLRFunc() bool {
lrfunc := this.commit()
lastnode := this.lastNode()
func (p *parser) parseLRFunc() bool {
lrfunc := p.commit()
lastnode := p.lastNode()
if lastnode != nil {
this.curr = lastnode.Push(NewLRFuncToken(lrfunc))
p.curr = lastnode.Push(NewLRFuncToken(lrfunc))
} else {
this.state = nil
p.state = nil
panic(fmt.Sprintf("expecting a value before operator %q", lrfunc))
}
return false
}
func (this *parser) ParseText() string {
scan := this.scan
func (p *parser) ParseText() string {
scan := p.scan
r := scan.Next()
if r == '"' || r == '\'' {
scan.Ignore()

View File

@ -1,16 +1,16 @@
// Modified from github.com/zdebeer99/goexpression
package filter
func (this *parser) pumpExpression() {
this.state = branchExpressionValuePart
for this.state != nil {
if this.err != nil {
func (p *parser) pumpExpression() {
p.state = branchExpressionValuePart
for p.state != nil {
if p.err != nil {
break
}
this.state = this.state(this)
p.state = p.state(p)
}
endo := this.commit()
if len(endo) > 0 || !this.scan.IsEOF() {
endo := p.commit()
if len(endo) > 0 || !p.scan.IsEOF() {
panic("unexpected end of expression '" + endo + "' not parsed")
}
}
@ -68,7 +68,6 @@ func branchFunctionArguments(this *parser) stateFn {
ftoken, ok := this.curr.Value.(*FuncToken)
if !ok {
panic("expecting function token to add arguments to")
return nil
}
state := branchExpressionValuePart
currnode := this.curr
@ -96,10 +95,8 @@ func branchFunctionArguments(this *parser) stateFn {
this.curr = currnode
if scan.IsEOF() {
panic("arguments missing end bracket")
return nil
}
panic("invalid char '" + string(r) + "' in arguments")
return nil
}
}

View File

@ -32,147 +32,144 @@ func NewScanner(template string) *Scanner {
return &Scanner{input: template}
}
func (this *Scanner) StartPosition() int {
return int(this.start)
func (s *Scanner) StartPosition() int {
return int(s.start)
}
func (this *Scanner) SetPosition(pos int) {
this.pos = Pos(pos)
func (s *Scanner) SetPosition(pos int) {
s.pos = Pos(pos)
}
func (this *Scanner) SetStartPosition(pos int) {
this.start = Pos(pos)
func (s *Scanner) SetStartPosition(pos int) {
s.start = Pos(pos)
}
// Token return the current selected text and move the start position to the current position
func (this *Scanner) Commit() string {
r1 := this.input[this.start:this.pos]
this.start = this.pos
this.prevState = this.SaveState()
func (s *Scanner) Commit() string {
r1 := s.input[s.start:s.pos]
s.start = s.pos
s.prevState = s.SaveState()
return r1
}
// IsEOF check if the end of the current string has been reached.
func (this *Scanner) IsEOF() bool {
return int(this.pos) >= len(this.input)
func (s *Scanner) IsEOF() bool {
return int(s.pos) >= len(s.input)
}
func (this *Scanner) Size() int {
return len(this.input)
func (s *Scanner) Size() int {
return len(s.input)
}
func (this *Scanner) MoveStart(pos int) {
this.start = this.start + Pos(pos)
func (s *Scanner) MoveStart(pos int) {
s.start = s.start + Pos(pos)
}
// Next returns the next rune in the input.
func (this *Scanner) Next() rune {
this.safebackup = true
if this.IsEOF() {
this.width = 0
func (s *Scanner) Next() rune {
s.safebackup = true
if s.IsEOF() {
s.width = 0
return eof
}
r, w := utf8.DecodeRuneInString(this.input[this.pos:])
this.width = Pos(w)
this.pos += this.width
this.curr = r
r, w := utf8.DecodeRuneInString(s.input[s.pos:])
s.width = Pos(w)
s.pos += s.width
s.curr = r
return r
}
func (this *Scanner) Skip() {
this.Next()
this.Commit()
func (s *Scanner) Skip() {
s.Next()
s.Commit()
}
// Peek returns but does not consume the next rune in the input.
func (this *Scanner) Peek() rune {
r := this.Next()
this.Backup()
func (s *Scanner) Peek() rune {
r := s.Next()
s.Backup()
return r
}
// Backup steps back one rune. Can only be called once per call of next.
func (this *Scanner) Backup() {
this.pos -= this.width
func (s *Scanner) Backup() {
s.pos -= s.width
}
// Rollback move the curr pos back to the start pos.
func (this *Scanner) Rollback() {
this.LoadState(this.prevState)
func (s *Scanner) Rollback() {
s.LoadState(s.prevState)
}
// Ignore skips over the pending input before this point.
func (this *Scanner) Ignore() {
this.start = this.pos
func (s *Scanner) Ignore() {
s.start = s.pos
}
// accept consumes the next rune if it's from the valid set.
func (this *Scanner) Accept(valid string) bool {
if strings.IndexRune(valid, this.Next()) >= 0 {
func (s *Scanner) Accept(valid string) bool {
if strings.ContainsRune(valid, s.Next()) {
return true
}
this.Backup()
s.Backup()
return false
}
// acceptRun consumes a run of runes from the valid set.
func (this *Scanner) AcceptRun(valid string) (found int) {
for strings.IndexRune(valid, this.Next()) >= 0 {
func (s *Scanner) AcceptRun(valid string) (found int) {
for strings.ContainsRune(valid, s.Next()) {
found++
}
this.Backup()
s.Backup()
return found
}
// runTo consumes a run of runes until an item in the valid set is found.
func (this *Scanner) RunTo(valid string) rune {
func (s *Scanner) RunTo(valid string) rune {
for {
r := this.Next()
r := s.Next()
if r == eof {
return r
}
if strings.IndexRune(valid, r) >= 0 {
if strings.ContainsRune(valid, r) {
return r
}
}
this.Backup()
return eof
}
func (this *Scanner) Prefix(pre string) bool {
if strings.HasPrefix(this.input[this.pos:], pre) {
this.pos += Pos(len(pre))
func (s *Scanner) Prefix(pre string) bool {
if strings.HasPrefix(s.input[s.pos:], pre) {
s.pos += Pos(len(pre))
return true
}
return false
}
func (this *Scanner) SkipSpaces() {
for IsSpace(this.Next()) {
func (s *Scanner) SkipSpaces() {
for IsSpace(s.Next()) {
}
this.Backup()
this.Ignore()
s.Backup()
s.Ignore()
}
func (this *Scanner) SkipToNewLine() {
func (s *Scanner) SkipToNewLine() {
for {
r := this.Next()
if this.IsEOF() {
r := s.Next()
if s.IsEOF() {
break
}
if r == '\n' {
break
}
}
this.Ignore()
return
s.Ignore()
}
// lineNumber reports which line we're on, based on the position of
// the previous item returned by nextItem. Doing it this way
// means we don't have to worry about peek double counting.
func (this *Scanner) LineNumber() int {
return 1 + strings.Count(this.input[:this.pos], "\n")
func (s *Scanner) LineNumber() int {
return 1 + strings.Count(s.input[:s.pos], "\n")
}
type ScannerState struct {
@ -181,10 +178,10 @@ type ScannerState struct {
width Pos
}
func (this *Scanner) SaveState() ScannerState {
return ScannerState{start: this.start, pos: this.pos, width: this.width}
func (s *Scanner) SaveState() ScannerState {
return ScannerState{start: s.start, pos: s.pos, width: s.width}
}
func (this *Scanner) LoadState(state ScannerState) {
this.start, this.pos, this.width = state.start, state.pos, state.width
func (s *Scanner) LoadState(state ScannerState) {
s.start, s.pos, s.width = state.start, state.pos, state.width
}

View File

@ -19,65 +19,65 @@ func IsNumber(r rune) bool {
// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
func IsAlphaNumeric(r rune) bool {
return unicode.IsLetter(r) || unicode.IsDigit(r) || strings.IndexRune(charValidString, r) >= 0
return unicode.IsLetter(r) || unicode.IsDigit(r) || strings.ContainsRune(charValidString, r)
}
func IsQoute(r rune) bool {
return strings.IndexRune("\"'", r) >= 0
return strings.ContainsRune("\"'", r)
}
func HasChar(r rune, accept string) bool {
return strings.IndexRune(accept, r) >= 0
return strings.ContainsRune(accept, r)
}
func (this *Scanner) Scan(valid func(r rune) bool) bool {
func (s *Scanner) Scan(valid func(r rune) bool) bool {
var isvalid bool
for valid(this.Next()) {
for valid(s.Next()) {
isvalid = true
}
this.Backup()
s.Backup()
return isvalid
}
//scan upto to the end of a word, returns true if a word was scanned.
//a word must start with a letter or '_' and can contain numbers after the first character.
func (this *Scanner) ScanWord() bool {
r := this.Next()
if unicode.IsLetter(r) || strings.IndexRune(charValidString, r) >= 0 {
// scan upto to the end of a word, returns true if a word was scanned.
// a word must start with a letter or '_' and can contain numbers after the first character.
func (s *Scanner) ScanWord() bool {
r := s.Next()
if unicode.IsLetter(r) || strings.ContainsRune(charValidString, r) {
for {
r = this.Next()
r = s.Next()
if IsAlphaNumeric(r) {
continue
} else {
this.Backup()
s.Backup()
return true
}
}
}
this.Backup()
s.Backup()
return false
}
func (this *Scanner) ScanNumber() bool {
state := this.SaveState()
r := this.Next()
func (s *Scanner) ScanNumber() bool {
state := s.SaveState()
r := s.Next()
isdigit := unicode.IsDigit(r)
if !isdigit && (r == '-' || r == '.') {
//if the first char is '-' or '.' the next char must be a digit.
if !unicode.IsDigit(this.Next()) {
this.LoadState(state)
if !unicode.IsDigit(s.Next()) {
s.LoadState(state)
return false
} else {
isdigit = true
}
} else if !isdigit {
this.Backup()
s.Backup()
return false
}
if this.Scan(IsNumber) || isdigit {
if s.Scan(IsNumber) || isdigit {
return true
} else {
this.LoadState(state)
s.LoadState(state)
return false
}
}

View File

@ -31,30 +31,22 @@ func NewEmptyToken() *EmptyToken {
return &EmptyToken{CatOther, nil}
}
func (this *EmptyToken) Category() TokenCategory {
return this.tokencat
func (t *EmptyToken) Category() TokenCategory {
return t.tokencat
}
func (this *EmptyToken) Error() error {
return this.err
func (t *EmptyToken) Error() error {
return t.err
}
func (this *EmptyToken) SetError(err error) {
this.err = err
func (t *EmptyToken) SetError(err error) {
t.err = err
}
func (this *EmptyToken) String() string {
func (t *EmptyToken) String() string {
return "Base()"
}
type ErrorToken struct {
EmptyToken
}
func NewErrorToken(err string) *ErrorToken {
return &ErrorToken{EmptyToken{CatOther, fmt.Errorf(err)}}
}
type NumberToken struct {
EmptyToken
Value int64
@ -65,14 +57,13 @@ func NewNumberToken(value string) *NumberToken {
val1, err := strconv.ParseInt(value, 10, 64)
if err != nil {
panic("number node failed to parse string to number (" + value + ")")
return node
}
node.Value = val1
return node
}
func (this *NumberToken) String() string {
return fmt.Sprintf("Number(%v)", this.Value)
func (t *NumberToken) String() string {
return fmt.Sprintf("Number(%v)", t.Value)
}
type IdentityToken struct {
@ -84,8 +75,8 @@ func NewIdentityToken(name string) *IdentityToken {
return &IdentityToken{EmptyToken{CatValue, nil}, name}
}
func (this *IdentityToken) String() string {
return fmt.Sprintf("Identity(%s)", this.Name)
func (t *IdentityToken) String() string {
return fmt.Sprintf("Identity(%s)", t.Name)
}
type FuncToken struct {
@ -98,16 +89,16 @@ func NewFuncToken(name string) *FuncToken {
return &FuncToken{EmptyToken{CatFunction, nil}, name, make([]*TreeNode, 0)}
}
func (this *FuncToken) AddArgument(arg *TreeNode) {
this.Arguments = append(this.Arguments, arg)
func (t *FuncToken) AddArgument(arg *TreeNode) {
t.Arguments = append(t.Arguments, arg)
}
func (this *FuncToken) String() string {
args := make([]string, len(this.Arguments))
for i, v := range this.Arguments {
args[i] = fmt.Sprintf("%s", strings.Replace(v.String(), "\n", ",", -1))
func (t *FuncToken) String() string {
args := make([]string, len(t.Arguments))
for i, v := range t.Arguments {
args[i] = strings.ReplaceAll(v.String(), "\n", ",")
}
return fmt.Sprintf("Func %s(%s)", this.Name, args)
return fmt.Sprintf("Func %s(%s)", t.Name, args)
}
type OperatorToken struct {
@ -122,36 +113,36 @@ func NewOperatorToken(operator string) *OperatorToken {
return op
}
func (this *OperatorToken) SetOperator(operator string) {
this.Operator = operator
this.lvl = operators.Level(operator)
if this.lvl < 0 {
func (t *OperatorToken) SetOperator(operator string) {
t.Operator = operator
t.lvl = operators.Level(operator)
if t.lvl < 0 {
panic(fmt.Sprintf("invalid operator %q", operator))
}
}
// OperatorPrecedence return true if the operator argument is lower than the current operator.
func (this *OperatorToken) Precedence(operator string) int {
func (t *OperatorToken) Precedence(operator string) int {
lvl := operators.Level(operator)
switch {
case lvl == this.lvl:
case lvl == t.lvl:
return 0
case lvl > this.lvl:
case lvl > t.lvl:
return 1
case lvl < this.lvl:
case lvl < t.lvl:
return -1
}
panic("unreachable code")
}
func (this *OperatorToken) String() string {
return fmt.Sprintf("Func(%s)", this.Operator)
func (t *OperatorToken) String() string {
return fmt.Sprintf("Func(%s)", t.Operator)
}
type OperatorPrecedence [][]string
func (this OperatorPrecedence) Level(operator string) int {
for level, operators := range this {
func (op OperatorPrecedence) Level(operator string) int {
for level, operators := range op {
for _, op := range operators {
if op == strings.ToLower(operator) {
return 5 - level
@ -161,12 +152,10 @@ func (this OperatorPrecedence) Level(operator string) int {
return -1
}
func (this OperatorPrecedence) All() []string {
func (op OperatorPrecedence) All() []string {
out := make([]string, 0)
for _, operators := range this {
for _, op := range operators {
out = append(out, op)
}
for _, operators := range op {
out = append(out, operators...)
}
return out
}
@ -190,8 +179,8 @@ func NewLRFuncToken(name string) *LRFuncToken {
return &LRFuncToken{EmptyToken{CatFunction, nil}, name}
}
func (this *LRFuncToken) String() string {
return fmt.Sprintf("Func(%s)", this.Name)
func (t *LRFuncToken) String() string {
return fmt.Sprintf("Func(%s)", t.Name)
}
type GroupToken struct {
@ -203,8 +192,8 @@ func NewGroupToken(group string) *GroupToken {
return &GroupToken{EmptyToken{CatOther, nil}, group}
}
func (this *GroupToken) String() string {
return fmt.Sprintf("Group(%s)", this.GroupType)
func (t *GroupToken) String() string {
return fmt.Sprintf("Group(%s)", t.GroupType)
}
type TextToken struct {
@ -216,6 +205,6 @@ func NewTextToken(text string) *TextToken {
return &TextToken{EmptyToken{CatValue, nil}, text}
}
func (this *TextToken) String() string {
return fmt.Sprintf("%q", this.Text)
func (t *TextToken) String() string {
return fmt.Sprintf("%q", t.Text)
}

View File

@ -18,12 +18,12 @@ func NewTreeNode(value Token) *TreeNode {
}
// Parent Returns the current element parent
func (this *TreeNode) Parent() *TreeNode {
return this.parent
func (n *TreeNode) Parent() *TreeNode {
return n.parent
}
func (this *TreeNode) Root() *TreeNode {
p := this
func (n *TreeNode) Root() *TreeNode {
p := n
for p.parent != nil {
p = p.parent
}
@ -32,43 +32,43 @@ func (this *TreeNode) Root() *TreeNode {
// setParent sets the current nodes parent value.
// Warning: does not add the node as a child
func (this *TreeNode) setParent(element *TreeNode) {
if this.parent != nil {
func (n *TreeNode) setParent(element *TreeNode) {
if n.parent != nil {
panic("TreeNode already attached to a parent node")
}
this.parent = element
n.parent = element
}
func (this *TreeNode) LastElement() *TreeNode {
if len(this.items) == 0 {
func (n *TreeNode) LastElement() *TreeNode {
if len(n.items) == 0 {
return nil
}
return this.items[len(this.items)-1]
return n.items[len(n.items)-1]
}
func (this *TreeNode) Last() Token {
last := this.LastElement()
func (n *TreeNode) Last() Token {
last := n.LastElement()
if last != nil {
return last.Value
}
return nil
}
func (this *TreeNode) Items() []*TreeNode {
return this.items
func (n *TreeNode) Items() []*TreeNode {
return n.items
}
// Add adds a TreeElement to the end of the children items of the current node.
func (this *TreeNode) AddElement(element *TreeNode) *TreeNode {
element.setParent(this)
this.items = append(this.items, element)
func (n *TreeNode) AddElement(element *TreeNode) *TreeNode {
element.setParent(n)
n.items = append(n.items, element)
return element
}
// Add adds a value to the end of the children items of the current node.
func (this *TreeNode) Add(value Token) *TreeNode {
func (n *TreeNode) Add(value Token) *TreeNode {
element := NewTreeNode(value)
return this.AddElement(element)
return n.AddElement(element)
}
// Push, removes the current element from its current parent, place the new value
@ -78,27 +78,27 @@ func (this *TreeNode) Add(value Token) *TreeNode {
// tree: A(B)
// B.Push(C)
// tree: A(C(B))
func (this *TreeNode) PushElement(element *TreeNode) *TreeNode {
parent := this.Parent()
func (n *TreeNode) PushElement(element *TreeNode) *TreeNode {
parent := n.Parent()
if parent != nil {
//replace the current node with the new node
index := parent.indexOf(this)
index := parent.indexOf(n)
parent.items[index] = element
element.setParent(parent)
this.parent = nil
n.parent = nil
}
//add the current node to the new node
element.AddElement(this)
element.AddElement(n)
return element
}
func (this *TreeNode) Push(value Token) *TreeNode {
return this.PushElement(NewTreeNode(value))
func (n *TreeNode) Push(value Token) *TreeNode {
return n.PushElement(NewTreeNode(value))
}
// FindChildElement Finds a child element in the current nodes children
func (this *TreeNode) indexOf(element *TreeNode) int {
for i, v := range this.items {
func (n *TreeNode) indexOf(element *TreeNode) int {
for i, v := range n.items {
if v == element {
return i
}
@ -106,23 +106,23 @@ func (this *TreeNode) indexOf(element *TreeNode) int {
return -1
}
func (this *TreeNode) StringContent() string {
lines := make([]string, len(this.items))
for i, v := range this.items {
func (n *TreeNode) StringContent() string {
lines := make([]string, len(n.items))
for i, v := range n.items {
lines[i] = v.String()
}
if this.Value.Error() != nil {
return fmt.Sprintf("[ERROR: %s]", this.Value.Error())
if n.Value.Error() != nil {
return fmt.Sprintf("[ERROR: %s]", n.Value.Error())
} else if len(lines) > 0 {
return fmt.Sprintf("%s", strings.Join(lines, ","))
return strings.Join(lines, ",")
} else {
return ""
}
}
func (this *TreeNode) String() string {
if this.StringContent() == "" {
return this.Value.String()
func (n *TreeNode) String() string {
if n.StringContent() == "" {
return n.Value.String()
}
return fmt.Sprintf("[%s:%s]", this.Value.String(), this.StringContent())
return fmt.Sprintf("[%s:%s]", n.Value.String(), n.StringContent())
}