func (b *Builder) ParseAssignment(ctx *builderCtx) node.Node { symbol := b.NextNonSpace(ctx) if symbol.Type() != ItemIdentifier { b.Unexpected(ctx, "Expected identifier, got %s", symbol) } b.DeclareLocalVarIfNew(ctx, symbol) n := node.NewAssignmentNode(symbol.Pos(), symbol.Value()) eq := b.NextNonSpace(ctx) switch eq.Type() { case ItemAssign: n.Expression = b.ParseExpression(ctx, false) case ItemAssignAdd: add := node.NewPlusNode(symbol.Pos()) add.Left = b.LocalVarOrFetchSymbol(ctx, symbol) add.Right = b.ParseExpression(ctx, false) n.Expression = add case ItemAssignSub: sub := node.NewMinusNode(symbol.Pos()) sub.Left = b.LocalVarOrFetchSymbol(ctx, symbol) sub.Right = b.ParseExpression(ctx, false) n.Expression = sub case ItemAssignMul: mul := node.NewMulNode(symbol.Pos()) mul.Left = b.LocalVarOrFetchSymbol(ctx, symbol) mul.Right = b.ParseExpression(ctx, false) n.Expression = mul case ItemAssignDiv: div := node.NewDivNode(symbol.Pos()) div.Left = b.LocalVarOrFetchSymbol(ctx, symbol) div.Right = b.ParseExpression(ctx, false) n.Expression = div default: b.Unexpected(ctx, "Expected assign, got %s", eq) } return n }
func (b *Builder) ParseExpression(ctx *builderCtx, canPrint bool) (n node.Node) { defer func() { if n != nil && canPrint { n = node.NewPrintNode(n.Pos(), n) } }() switch b.PeekNonSpace(ctx).Type() { case ItemOpenParen: // Looks like a group of something n = b.ParseGroup(ctx) case ItemOpenSquareBracket: // Looks like an inline list def n = b.ParseMakeArray(ctx) default: // Otherwise it's a straight forward ... something n = b.ParseTerm(ctx) if n == nil { panic(fmt.Sprintf("Expected term but could not parse. Next is %s\n", b.PeekNonSpace(ctx))) } } next := b.PeekNonSpace(ctx) switch n.Type() { case node.LocalVar, node.FetchSymbol: switch next.Type() { case ItemPeriod: // It's either a method call, or a map lookup b.NextNonSpace(ctx) n = b.ParseMethodCallOrMapLookup(ctx, n) case ItemOpenSquareBracket: n = b.ParseArrayElementFetch(ctx, n) case ItemOpenParen: // A variable followed by an open paren is a function call n = b.ParseFunCall(ctx, n) } } next = b.NextNonSpace(ctx) switch next.Type() { case ItemPlus: tmp := node.NewPlusNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp return case ItemMinus: // This is special... following := b.PeekNonSpace(ctx) if following.Type() == ItemTagEnd { b.Backup2(ctx, next) // Postchomp! not arithmetic! return } tmp := node.NewMinusNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp return case ItemAsterisk: tmp := node.NewMulNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp return case ItemSlash: tmp := node.NewDivNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp return case ItemEquals: tmp := node.NewEqualsNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp case ItemNotEquals: tmp := node.NewNotEqualsNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp case ItemLT: tmp := node.NewLTNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp return case ItemGT: tmp := node.NewGTNode(next.Pos()) tmp.Left = n tmp.Right = b.ParseExpression(ctx, false) n = tmp case ItemVerticalSlash: b.Backup(ctx) n = b.ParseFilter(ctx, n) default: b.Backup(ctx) } return }