github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/parse_vars.go (about)

     1  package expressions
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/lmorg/murex/lang/expressions/primitives"
     7  	"github.com/lmorg/murex/lang/types"
     8  	"github.com/lmorg/murex/utils/home"
     9  )
    10  
    11  func (tree *ParserT) parseVarScalarExpr(exec, execScalars bool, strOrVal varFormatting) ([]rune, interface{}, string, primitives.FunctionT, error) {
    12  	runes, v, mxDt, err := tree.parseVarScalar(exec, execScalars, varAsValue)
    13  
    14  	if exec {
    15  		fn := func() (*primitives.Value, error) {
    16  			switch t := v.(type) {
    17  			case *getVarIndexOrElementT:
    18  				val, mxDt, err := tree.getVarIndexOrElement(t)
    19  				return &primitives.Value{Value: val, DataType: mxDt}, err
    20  
    21  			case parseLambdaExecTrueT:
    22  				_, val, mxDt, err := t()
    23  				return &primitives.Value{Value: val, DataType: mxDt}, err
    24  
    25  			default:
    26  				val, mxDt, err := tree.getVar(scalarNameDetokenised(runes), varAsValue)
    27  				return &primitives.Value{Value: val, DataType: mxDt}, err
    28  			}
    29  		}
    30  		return runes, v, mxDt, fn, err
    31  	}
    32  
    33  	return runes, v, mxDt, nil, err
    34  }
    35  
    36  func (tree *ParserT) parseVarScalar(exec, execScalars bool, strOrVal varFormatting) ([]rune, interface{}, string, error) {
    37  	if tree.nextChar() == '(' {
    38  		tree.charPos++
    39  		return tree.parseVarParenthesis(execScalars, strOrVal)
    40  	}
    41  
    42  	if !isBareChar(tree.nextChar()) {
    43  		// always print $
    44  		return []rune{'$'}, "$", types.String, nil
    45  	}
    46  
    47  	tree.charPos++
    48  	value := tree.parseBareword()
    49  
    50  	if tree.charPos < len(tree.expression) && tree.expression[tree.charPos] == '[' {
    51  		return tree.parseVarIndexElement(execScalars, '$', value, strOrVal)
    52  	}
    53  
    54  	tree.charPos--
    55  
    56  	r := append([]rune{'$'}, value...)
    57  
    58  	// don't getVar() until we come to execute the expression, skip when only
    59  	// parsing syntax
    60  	if execScalars {
    61  		v, dataType, err := tree.getVar(value, strOrVal)
    62  		return r, v, dataType, err
    63  	}
    64  
    65  	return r, nil, "", nil
    66  }
    67  
    68  func (tree *ParserT) parseVarParenthesis(exec bool, strOrVal varFormatting) ([]rune, interface{}, string, error) {
    69  	start := tree.charPos
    70  
    71  	for tree.charPos++; tree.charPos < len(tree.expression); tree.charPos++ {
    72  		r := tree.expression[tree.charPos]
    73  
    74  		switch {
    75  		case r == ')':
    76  			goto endParenthesis
    77  		}
    78  	}
    79  
    80  	return nil, nil, "", raiseError(
    81  		tree.expression, nil, tree.charPos, "expecting closing parenthesis, ')', after variable reference")
    82  
    83  endParenthesis:
    84  	path := tree.expression[start+1 : tree.charPos]
    85  	value := tree.expression[start-1 : tree.charPos+1]
    86  
    87  	if !exec {
    88  		return value, nil, "", nil
    89  	}
    90  
    91  	v, dt, err := tree.getVar(path, strOrVal)
    92  	if err != nil {
    93  		return value, nil, "", err
    94  	}
    95  	return value, v, dt, nil
    96  }
    97  
    98  func (tree *ParserT) parseVarIndexElement(exec bool, sigil rune, varName []rune, strOrVal varFormatting) ([]rune, interface{}, string, error) {
    99  	if tree.nextChar() == '{' {
   100  		//return tree.parseLambdaScala(exec, '$', varName, strOrVal)
   101  		//return tree.parseLambdaStatement(exec, '$')
   102  		if exec {
   103  			return tree.parseLambdaExecTrue(varName, sigil, "")
   104  		}
   105  		r, err := tree.parseLambdaExecFalse(sigil, varName)
   106  		value := append([]rune{sigil}, varName...)
   107  		value = append(value, r...)
   108  		value = append(value, ']')
   109  		var fn parseLambdaExecTrueT = func() ([]rune, any, string, error) {
   110  			return _parseLambdaExecTrue(tree.p, varName, sigil, "", value, r[1:], tree.StrictArrays())
   111  		}
   112  		return value, fn, "", err
   113  	}
   114  
   115  	var (
   116  		brackets = 1
   117  		escape   bool
   118  		getIorE  = new(getVarIndexOrElementT)
   119  	)
   120  
   121  	start := tree.charPos
   122  
   123  	if tree.nextChar() == '[' {
   124  		brackets++
   125  		tree.charPos++
   126  	}
   127  
   128  	tree.charPos++
   129  
   130  	getIorE.isIorE = brackets
   131  
   132  	for ; tree.charPos < len(tree.expression); tree.charPos++ {
   133  		r := tree.expression[tree.charPos]
   134  
   135  		switch {
   136  		case escape:
   137  			escape = false
   138  
   139  		case r == '\\':
   140  			escape = true
   141  
   142  		case r == '[':
   143  			return nil, "", "", raiseError(
   144  				tree.expression, nil, tree.charPos, "too many nested square '[' brackets")
   145  
   146  		case r == ']':
   147  			brackets--
   148  			if brackets == 0 {
   149  				goto endIndexElement
   150  			}
   151  		}
   152  	}
   153  
   154  	return nil, nil, "", raiseError(
   155  		tree.expression, nil, tree.charPos, "missing closing bracket ']'")
   156  
   157  endIndexElement:
   158  	value := tree.expression[start-len(varName)-1 : tree.charPos+1]
   159  	getIorE.varName = varName
   160  	getIorE.key = tree.expression[start+getIorE.isIorE : tree.charPos-getIorE.isIorE+1]
   161  	getIorE.strOrVal = strOrVal
   162  
   163  	if !exec {
   164  		return value, getIorE, "", nil
   165  	}
   166  
   167  	v, dt, err := tree.getVarIndexOrElement(getIorE)
   168  	if err != nil {
   169  		return nil, nil, "", err
   170  	}
   171  	return nil, v, dt, nil
   172  }
   173  
   174  func (tree *ParserT) parseVarArray(exec bool) ([]rune, interface{}, error) {
   175  	if !isBareChar(tree.nextChar()) {
   176  		return nil, nil, errors.New("'@' symbol found but no variable name followed")
   177  	}
   178  
   179  	tree.charPos++
   180  	value := tree.parseBareword()
   181  
   182  	if tree.charPos < len(tree.expression) && tree.expression[tree.charPos] == '[' {
   183  		return tree.parseVarRange(exec, value)
   184  	}
   185  
   186  	tree.charPos--
   187  
   188  	if !exec {
   189  		// don't getArray() until we come to execute the expression, skip when only
   190  		// parsing syntax
   191  		return append([]rune{'@'}, value...), nil, nil
   192  	}
   193  
   194  	v, err := tree.getArray(value)
   195  	return value, v, err
   196  }
   197  
   198  func (tree *ParserT) parseVarRange(exec bool, varName []rune) ([]rune, interface{}, error) {
   199  	if tree.nextChar() == '{' {
   200  		if exec {
   201  			r, v, _, err := tree.parseLambdaExecTrue(varName, '@', "") // TODO: test me
   202  			return r, v, err
   203  		} else {
   204  			// just parsing source
   205  			//r, _, err := tree.parseSubShell(false, '@', varAsValue)
   206  			r, err := tree.parseLambdaExecFalse('@', nil)
   207  			return r, nil, err
   208  
   209  			//r, v, _, err := tree.parseLambdaScala(false, '@', varName, varAsValue) // just parsing source
   210  			//return r, v, err
   211  		}
   212  	}
   213  
   214  	var escape bool
   215  
   216  	start := tree.charPos
   217  
   218  	for tree.charPos++; tree.charPos < len(tree.expression); tree.charPos++ {
   219  		r := tree.expression[tree.charPos]
   220  
   221  		switch {
   222  		case escape:
   223  			escape = false
   224  
   225  		case r == '\\':
   226  			escape = true
   227  
   228  		case r == '[':
   229  			return nil, "", raiseError(
   230  				tree.expression, nil, tree.charPos, "too many nested square '[' brackets")
   231  
   232  		case r == ']':
   233  			goto endRange
   234  		}
   235  	}
   236  
   237  	return nil, "", raiseError(
   238  		tree.expression, nil, tree.charPos, "missing closing bracket ']'")
   239  
   240  endRange:
   241  	key := tree.expression[start+1 : tree.charPos]
   242  	flags := []rune{}
   243  	if isBareChar(tree.nextChar()) {
   244  		tree.charPos++
   245  		flags = tree.parseBareword()
   246  		tree.charPos--
   247  	}
   248  	value := tree.expression[start-len(varName)-1 : tree.charPos]
   249  
   250  	if !exec {
   251  		return value, "", nil
   252  	}
   253  
   254  	v, err := tree.getVarRange(varName, key, flags)
   255  	if err != nil {
   256  		return nil, "", err
   257  	}
   258  	return nil, v, nil
   259  }
   260  
   261  func isUserNameChar(r rune) bool {
   262  	return isBareChar(r) || r == '.' || r == '-'
   263  }
   264  
   265  func (tree *ParserT) parseVarTilde(exec bool) string {
   266  	tree.charPos++
   267  	start := tree.charPos
   268  
   269  	for ; tree.charPos < len(tree.expression); tree.charPos++ {
   270  		switch {
   271  		case isUserNameChar(tree.expression[tree.charPos]):
   272  			// valid user name
   273  
   274  		default:
   275  			// not a valid username character
   276  			goto endTilde
   277  		}
   278  	}
   279  
   280  endTilde:
   281  	user := string(tree.expression[start:tree.charPos])
   282  	tree.charPos--
   283  
   284  	if !exec {
   285  		return "~" + user
   286  	}
   287  
   288  	if len(user) == 0 {
   289  		return home.MyDir
   290  	}
   291  
   292  	return home.UserDir(user)
   293  }