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

     1  package expressions
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  
     7  	"github.com/lmorg/murex/lang"
     8  	"github.com/lmorg/murex/lang/expressions/primitives"
     9  	"github.com/lmorg/murex/lang/expressions/symbols"
    10  	"github.com/lmorg/murex/lang/types"
    11  	"github.com/lmorg/murex/utils/consts"
    12  )
    13  
    14  type astNodeT struct {
    15  	key    symbols.Exp
    16  	value  []rune
    17  	pos    int
    18  	offset int
    19  	dt     *primitives.DataType
    20  }
    21  
    22  func (node *astNodeT) Value() string {
    23  	return string(node.value)
    24  }
    25  
    26  type ParserT struct {
    27  	ast           []*astNodeT
    28  	statement     *StatementT
    29  	charPos       int
    30  	charOffset    int
    31  	astPos        int
    32  	startRow      int
    33  	endRow        int
    34  	startCol      int
    35  	endCol        int
    36  	expression    []rune
    37  	subExp        bool
    38  	p             *lang.Process
    39  	_strictTypes  interface{}
    40  	_strictArrays interface{}
    41  	_expandGlob   interface{}
    42  }
    43  
    44  func (tree *ParserT) nextChar() rune {
    45  	if tree.charPos+1 >= len(tree.expression) {
    46  		return 0
    47  	}
    48  	return tree.expression[tree.charPos+1]
    49  }
    50  
    51  func (tree *ParserT) prevChar() rune {
    52  	if tree.charPos < 1 {
    53  		return 0
    54  	}
    55  	return tree.expression[tree.charPos-1]
    56  }
    57  
    58  func (tree *ParserT) crLf() {
    59  	tree.endRow++
    60  	tree.endCol = tree.charPos
    61  }
    62  
    63  func (tree *ParserT) GetColumnN() int { return tree.charOffset - tree.startCol + 2 }
    64  func (tree *ParserT) GetLineN() int   { return tree.startRow }
    65  
    66  func (tree *ParserT) appendAst(key symbols.Exp, value ...rune) {
    67  	tree.ast = append(tree.ast, &astNodeT{
    68  		key:    key,
    69  		value:  value,
    70  		pos:    tree.charPos - len(value),
    71  		offset: tree.charOffset,
    72  	})
    73  }
    74  
    75  func (tree *ParserT) appendAstWithPrimitive(key symbols.Exp, dt *primitives.DataType, value ...rune) {
    76  	tree.ast = append(tree.ast, &astNodeT{
    77  		key:    key,
    78  		value:  value,
    79  		pos:    tree.charPos - len(value),
    80  		offset: tree.charOffset,
    81  		dt:     dt,
    82  	})
    83  }
    84  
    85  func (tree *ParserT) foldAst(new *astNodeT) error {
    86  	switch {
    87  	case tree.astPos <= 0:
    88  		return fmt.Errorf("cannot fold when tree.astPos<%d> <= 0<%d> (%s)",
    89  			tree.astPos, len(tree.ast), consts.IssueTrackerURL)
    90  
    91  	case tree.astPos >= len(tree.ast)-1:
    92  		return fmt.Errorf("cannot fold when tree.astPos<%d> >= len(tree.ast)-1<%d> (%s)",
    93  			tree.astPos, len(tree.ast), consts.IssueTrackerURL)
    94  
    95  	case len(tree.ast) == 3:
    96  		tree.ast = []*astNodeT{new}
    97  
    98  	case tree.astPos == 1:
    99  		tree.ast = append([]*astNodeT{new}, tree.ast[3:]...)
   100  
   101  	case tree.astPos == len(tree.ast)-2:
   102  		tree.ast = append(tree.ast[:len(tree.ast)-3], new)
   103  
   104  	default:
   105  		start := append(tree.ast[:tree.astPos-1], new)
   106  		end := tree.ast[tree.astPos+2:]
   107  		tree.ast = append(start, end...)
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  // memory safe
   114  func (tree *ParserT) prevSymbol() *astNodeT {
   115  	if tree.astPos-1 < 0 {
   116  		return nil
   117  	}
   118  
   119  	return tree.ast[tree.astPos-1]
   120  }
   121  
   122  // memory safe
   123  func (tree *ParserT) currentSymbol() *astNodeT {
   124  	if tree.astPos < 0 || tree.astPos >= len(tree.ast) {
   125  		return nil
   126  	}
   127  
   128  	return tree.ast[tree.astPos]
   129  }
   130  
   131  // memory safe
   132  func (tree *ParserT) nextSymbol() *astNodeT {
   133  	if tree.astPos+1 >= len(tree.ast) {
   134  		return nil
   135  	}
   136  
   137  	return tree.ast[tree.astPos+1]
   138  }
   139  
   140  func (tree *ParserT) getLeftAndRightSymbols() (*astNodeT, *astNodeT, error) {
   141  	left := tree.prevSymbol()
   142  	right := tree.nextSymbol()
   143  
   144  	if left == nil {
   145  		return nil, nil, raiseError(tree.expression, tree.ast[tree.astPos], 0, "missing value left of operation")
   146  	}
   147  
   148  	if right == nil {
   149  		return nil, nil, raiseError(tree.expression, tree.ast[tree.astPos], 0, "missing value right of operation")
   150  	}
   151  
   152  	return left, right, nil
   153  }
   154  
   155  func node2primitive(node *astNodeT) (*primitives.DataType, error) {
   156  	switch node.key {
   157  	case symbols.Number:
   158  		f, err := strconv.ParseFloat(node.Value(), 64)
   159  		if err != nil {
   160  			return nil, raiseError(nil, node, 0, err.Error())
   161  		}
   162  		return primitives.NewPrimitive(primitives.Number, f), nil
   163  
   164  	case symbols.QuoteSingle, symbols.QuoteDouble, symbols.QuoteParenthesis:
   165  		return primitives.NewPrimitive(primitives.String, node.Value()), nil
   166  
   167  	case symbols.Boolean:
   168  		return primitives.NewPrimitive(
   169  			primitives.Boolean,
   170  			types.IsTrueString(string(node.value), 0),
   171  		), nil
   172  
   173  	case symbols.Bareword:
   174  		return primitives.NewPrimitive(primitives.Bareword, nil), nil
   175  
   176  	case symbols.Calculated, symbols.Scalar, symbols.SubExpressionBegin:
   177  		return primitives.NewPrimitive(primitives.Null, nil), nil
   178  
   179  	case symbols.Null:
   180  		return primitives.NewPrimitive(primitives.Null, nil), nil
   181  
   182  	}
   183  
   184  	return nil, raiseError(nil, node, 0, fmt.Sprintf("unexpected error converting node to primitive (%s)", consts.IssueTrackerURL))
   185  }
   186  
   187  func (tree *ParserT) StrictTypes() bool {
   188  	if tree._strictTypes != nil {
   189  		return tree._strictTypes.(bool)
   190  	}
   191  
   192  	var err error
   193  	tree._strictTypes, err = tree.p.Config.Get("proc", "strict-types", types.Boolean)
   194  	if err != nil {
   195  		panic(err)
   196  	}
   197  
   198  	return tree._strictTypes.(bool)
   199  }
   200  
   201  func (tree *ParserT) StrictArrays() bool {
   202  	if tree._strictArrays != nil {
   203  		return tree._strictArrays.(bool)
   204  	}
   205  
   206  	var err error
   207  	tree._strictArrays, err = tree.p.Config.Get("proc", "strict-arrays", types.Boolean)
   208  	if err != nil {
   209  		panic(err)
   210  	}
   211  
   212  	return tree._strictArrays.(bool)
   213  }
   214  
   215  func (tree *ParserT) ExpandGlob() bool {
   216  	if tree._expandGlob != nil {
   217  		return tree._expandGlob.(bool)
   218  	}
   219  
   220  	var err error
   221  	tree._expandGlob, err = tree.p.Config.Get("shell", "expand-globs", types.Boolean)
   222  	if err != nil {
   223  		panic(err)
   224  	}
   225  
   226  	tree._expandGlob = tree._expandGlob.(bool) && tree.p.Scope.Id == lang.ShellProcess.Id &&
   227  		tree.p.Parent.Id == lang.ShellProcess.Id && !tree.p.Background.Get() && lang.Interactive
   228  
   229  	return tree._expandGlob.(bool)
   230  }