github.com/Rookout/GoSDK@v0.1.48/pkg/processor/paths/maps_actions.go (about)

     1  package paths
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/Rookout/GoSDK/pkg/rookoutErrors"
     6  	"github.com/Rookout/GoSDK/pkg/utils"
     7  	"github.com/yhirose/go-peg"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  type mapsActions struct {
    13  	operations []pathOperation
    14  	parser     *peg.Parser
    15  }
    16  
    17  func newMapsActions() (m *mapsActions, err rookoutErrors.RookoutError) {
    18  	m = &mapsActions{}
    19  	m.parser, err = m.buildParser()
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  	return m, nil
    24  }
    25  
    26  func (m *mapsActions) buildParser() (*peg.Parser, rookoutErrors.RookoutError) {
    27  	
    28  	parser, err := peg.NewParser(`
    29  		COMPARISON_EXPRESSION   <-  EXPRESSION (COMPARISON EXPRESSION)*
    30  		EXPRESSION   			<-  ATOM (COMPARISON ATOM)*
    31  		
    32  		#For some reason the whitespaces are ignored - causing parsing errors
    33  		LIST		 <-  [ "["] ([ \t]*ATOM ([ \t]*[,][ \t]* ATOM)*)? ["\]" ][ \t]*
    34          ATOM         <-  NULL / FLOAT / NUMBER / '(' EXPRESSION ')' / '(' COMPARISON_EXPRESSION ')' / CHAR / STRING / APOSTROPHE_STRING / BOOL / LIST / NAMESPACE
    35  		COMPARISON   <-  <'+'/'-'/'/'/'*'/'<='/'>='/'!='/'=='/"="/'>'/'<'/"LT"/"GT"/"LE"/"GE"/"EQ"/"NE"/"lt"/"gt"/"le"/"ge"/"eq"/"ne"/"in"/"IN"/"or"/"OR"/"||"/"and"/"AND"/"&&">
    36  		NUMBER       <-  < [-]?[0-9]+ >
    37          FLOAT        <-  < [-]?[0-9]+([.][0-9]+)+ >
    38  		#The only value we are not capturing here is '"' (")
    39  		STRING       <-  < [\"] [ !#-~]* [\"] >
    40  		APOSTROPHE_STRING <- < ['] [ !-&(-~]* ['] >
    41  		BOOL		 <-  'True' / 'False' / 'true' / 'false'
    42  		CHAR       	 <-  < ['] [ !-~] ['] >
    43  		NULL		 <-  'None' / 'nil' / 'null' / 'undefined'
    44  
    45  		METHOD_ACCESS <- < ([a-zA-Z0-9_]+) > '(' < (ATOM ([,] ATOM)*)? > ')'
    46  		VARIABLE_ACCESS <- < ([a-zA-Z0-9_]+) >
    47  		MAP_ACCESS <- '[' < (ATOM) > ']'
    48  		NAMESPACE    <-   (METHOD_ACCESS / VARIABLE_ACCESS) (MAP_ACCESS / '.' METHOD_ACCESS / '.' VARIABLE_ACCESS)*
    49  
    50  		%whitespace  <-  [ \t]*
    51  		---
    52          # Expression parsing 1 is the least important
    53  		%expr  = EXPRESSION
    54  		%comparison = L + -  # level 1
    55  		%comparison = L * /  # level 2
    56  		%comparison = L > < # level 3
    57      `)
    58  	if nil != err {
    59  		return nil, rookoutErrors.NewArithmeticPathException(err)
    60  	}
    61  	grammar := parser.Grammar
    62  
    63  	grammar["COMPARISON_EXPRESSION"].Action = m.makeComparisonExpression
    64  	grammar["EXPRESSION"].Action = m.makeComparisonExpression
    65  	grammar["COMPARISON"].Action = m.makeComparison
    66  	grammar["LIST"].Action = m.makeList
    67  	grammar["BOOL"].Action = m.makeBoolean
    68  	grammar["NAMESPACE"].Action = m.makeNamespace
    69  	grammar["VARIABLE_ACCESS"].Action = m.makeAttributeOperation
    70  	grammar["METHOD_ACCESS"].Action = m.makeMethodOperation
    71  	grammar["MAP_ACCESS"].Action = m.makeLookupOperation
    72  	grammar["FLOAT"].Action = m.makeFloat
    73  	grammar["NUMBER"].Action = m.makeNumber
    74  	grammar["STRING"].Action = m.makeString
    75  	grammar["APOSTROPHE_STRING"].Action = m.makeString
    76  	grammar["CHAR"].Action = m.makeString
    77  	grammar["NULL"].Action = m.makeNull
    78  
    79  	return parser, nil
    80  }
    81  
    82  func (m *mapsActions) Parse(path string) (node, rookoutErrors.RookoutError) {
    83  	operations, err := m.parser.ParseAndGetValue(path, nil)
    84  	if err != nil {
    85  		return nil, rookoutErrors.NewRookInvalidArithmeticPathException(path, err)
    86  	}
    87  	return operations.(node), nil
    88  }
    89  
    90  func (m *mapsActions) GetWriteOperations() []pathOperation {
    91  	return m.operations
    92  }
    93  
    94  func (m *mapsActions) makeComparisonExpression(values *peg.Values, _ peg.Any) (peg.Any, error) {
    95  	if values.Len() == 2 {
    96  		return nil, rookoutErrors.NewRookInvalidArithmeticPathException(values.SS, nil)
    97  	}
    98  
    99  	elements := make([]node, 0, len(values.Vs))
   100  	for _, n := range values.Vs {
   101  		element, ok := n.(node)
   102  		if !ok {
   103  			return nil, rookoutErrors.NewRookInvalidArithmeticPathException(values.SS, nil)
   104  		}
   105  		elements = append(elements, element)
   106  	}
   107  
   108  	for len(elements) > 1 {
   109  		elementsChanged := false
   110  
   111  		for level := optLevel(0); level < NUM_OF_LEVELS && !elementsChanged; level++ {
   112  			for i := 1; i < len(elements); i += 2 {
   113  				left := elements[i-1]
   114  				opt, ok := elements[i].(*optNode)
   115  				if !ok {
   116  					return nil, rookoutErrors.NewRookInvalidArithmeticPathException(values.SS, nil)
   117  				}
   118  				right := elements[i+1]
   119  
   120  				if opt.level != level {
   121  					continue
   122  				}
   123  
   124  				compNode := newComparisonNode(left, opt, right)
   125  				elements[i-1] = compNode
   126  				elements = append(elements[:i], elements[i+2:]...)
   127  
   128  				elementsChanged = true
   129  			}
   130  		}
   131  	}
   132  
   133  	return elements[0], nil
   134  }
   135  
   136  func (m *mapsActions) makeNamespace(values *peg.Values, _ peg.Any) (peg.Any, error) {
   137  	var operations []pathOperation
   138  	for _, rawOperation := range values.Vs {
   139  		if operation, ok := rawOperation.(pathOperation); ok {
   140  			operations = append(operations, operation)
   141  		} else {
   142  			msg := fmt.Sprintf("parsing %v in (%s)", rawOperation, values.SS)
   143  			return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil)
   144  		}
   145  	}
   146  
   147  	m.operations = append(m.operations, operations...)
   148  	return newNamespaceNode(operations), nil
   149  }
   150  
   151  func (m *mapsActions) makeList(values *peg.Values, _ peg.Any) (peg.Any, error) {
   152  	a := make([]node, 0, len(values.Vs))
   153  	for _, s := range values.Vs {
   154  		a = append(a, s.(node))
   155  	}
   156  
   157  	return newListNode(a), nil
   158  }
   159  
   160  func (m *mapsActions) makeComparison(values *peg.Values, _ peg.Any) (peg.Any, error) {
   161  	opt := strings.Replace(values.Token(), " ", "", -1)
   162  	return newOpt(opt)
   163  }
   164  
   165  func (m *mapsActions) makeBoolean(values *peg.Values, _ peg.Any) (peg.Any, error) {
   166  	val := strings.ToLower(utils.ReplaceAll(values.Token(), " ", ""))
   167  	if val == "true" {
   168  		return newValueNode(true), nil
   169  	}
   170  	return newValueNode(false), nil
   171  }
   172  
   173  func (m *mapsActions) makeString(values *peg.Values, _ peg.Any) (peg.Any, error) {
   174  	return newValueNode(values.Token()[1 : len(values.Token())-1]), nil
   175  }
   176  
   177  func (m *mapsActions) makeNumber(values *peg.Values, _ peg.Any) (peg.Any, error) {
   178  	i, err := strconv.Atoi(values.Token())
   179  	if err != nil {
   180  		msg := "unable to parse int: " + values.Token()
   181  		return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, err)
   182  	}
   183  	return newValueNode(i), nil
   184  }
   185  
   186  func (m *mapsActions) makeFloat(values *peg.Values, _ peg.Any) (peg.Any, error) {
   187  	f, err := strconv.ParseFloat(values.Token(), 64)
   188  	if err != nil {
   189  		msg := "unable to parse float: " + values.Token()
   190  		return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, err)
   191  	}
   192  	return newValueNode(f), nil
   193  }
   194  
   195  func (m *mapsActions) makeLookupOperation(values *peg.Values, _ peg.Any) (peg.Any, error) {
   196  	return newLookupOperation(values.Token())
   197  }
   198  
   199  func (m *mapsActions) makeMethodOperation(values *peg.Values, _ peg.Any) (peg.Any, error) {
   200  	args := ""
   201  	if len(values.Ts) >= 2 {
   202  		args = values.Ts[1].S
   203  		if (strings.HasSuffix(args, "'") && strings.HasPrefix(args, "'")) ||
   204  			(strings.HasSuffix(args, "\"") && strings.HasPrefix(args, "\"")) {
   205  			args = args[1 : len(args)-1]
   206  		}
   207  	}
   208  	return newMethodOperation(values.Token(), args), nil
   209  }
   210  
   211  func (m *mapsActions) makeAttributeOperation(values *peg.Values, _ peg.Any) (peg.Any, error) {
   212  	return newAttributeOperation(values.Token()), nil
   213  }
   214  
   215  func (m *mapsActions) makeNull(_ *peg.Values, _ peg.Any) (peg.Any, error) {
   216  	return newNoneNode(), nil
   217  }