func (b *Builder) ParseMethodCallOrMapLookup(ctx *builderCtx, invocant node.Node) node.Node { // We have already seen identifier followed by a period symbol := b.NextNonSpace(ctx) if symbol.Type() != ItemIdentifier { b.Unexpected(ctx, "Expected identifier for method call or map lookup, got %s", symbol.Type()) } var n node.Node next := b.NextNonSpace(ctx) if next.Type() != ItemOpenParen { // it's a map lookup. Put back that extra token we read b.Backup(ctx) n = node.NewFetchFieldNode(invocant.Pos(), invocant, symbol.Value()) } else { // It's a method call! Parse the list args := b.ParseList(ctx) closeParen := b.NextNonSpace(ctx) if closeParen.Type() != ItemCloseParen { b.Unexpected(ctx, "Expected ')', got %s", closeParen.Type()) } n = node.NewMethodCallNode(invocant.Pos(), invocant, symbol.Value(), args.(*node.ListNode)) } // If we are followed by another period, we are going to have to // check for another level of methodcall / lookup if b.PeekNonSpace(ctx).Type() == ItemPeriod { b.NextNonSpace(ctx) // consume period return b.ParseMethodCallOrMapLookup(ctx, n) } return n }
func compile(ctx *context, n node.Node) { switch n.Type() { case node.Int, node.Text: compileLiteral(ctx, n) case node.FetchSymbol: compileFetchSymbol(ctx, n.(*node.TextNode)) case node.FetchField: compileFetchField(ctx, n.(*node.FetchFieldNode)) case node.FetchArrayElement: compileFetchArrayElement(ctx, n.(*node.BinaryNode)) case node.LocalVar: compileLoadLvar(ctx, n.(*node.LocalVarNode)) case node.Assignment: compileAssignment(ctx, n.(*node.AssignmentNode)) case node.Print: compilePrint(ctx, n.(*node.ListNode)) case node.PrintRaw: compilePrintRaw(ctx, n.(*node.ListNode)) case node.Foreach: compileForeach(ctx, n.(*node.ForeachNode)) case node.While: compileWhile(ctx, n.(*node.WhileNode)) case node.If: compileIf(ctx, n.(*node.IfNode)) case node.Else: compileElse(ctx, n.(*node.ElseNode)) case node.MakeArray: compileMakeArray(ctx, n.(*node.UnaryNode)) case node.Range: compileRange(ctx, n.(*node.BinaryNode)) case node.List: compileList(ctx, n.(*node.ListNode)) case node.FunCall: compileFunCall(ctx, n.(*node.FunCallNode)) case node.MethodCall: compileMethodCall(ctx, n.(*node.MethodCallNode)) case node.Include: compileInclude(ctx, n.(*node.IncludeNode)) case node.Group: compile(ctx, n.(*node.UnaryNode).Child) case node.Equals, node.NotEquals, node.LT, node.GT: compileComparison(ctx, n.(*node.BinaryNode)) case node.Plus, node.Minus, node.Mul, node.Div: compileBinaryArithmetic(ctx, n.(*node.BinaryNode)) case node.Filter: compileFilter(ctx, n.(*node.FilterNode)) case node.Wrapper: compileWrapper(ctx, n.(*node.WrapperNode)) case node.Macro: compileMacro(ctx, n.(*node.MacroNode)) default: fmt.Printf("Unknown node: %s\n", n.Type()) } }
func compileLiteral(ctx *context, n node.Node) { var op vm.Op switch n.Type() { case node.Int: op = ctx.AppendOp(vm.TXOPLiteral, n.(*node.NumberNode).Value.Int()) case node.Text: op = ctx.AppendOp(vm.TXOPLiteral, n.(*node.TextNode).Text) default: panic("unknown literal value") } op.SetComment("Save literal to sa") }
func (b *Builder) ParseFunCall(ctx *builderCtx, invocant node.Node) node.Node { next := b.NextNonSpace(ctx) if next.Type() != ItemOpenParen { b.Unexpected(ctx, "Expected '(', got %s", next.Type()) } args := b.ParseList(ctx) closeParen := b.NextNonSpace(ctx) if closeParen.Type() != ItemCloseParen { b.Unexpected(ctx, "Expected ')', got %s", closeParen.Type()) } return node.NewFunCallNode(invocant.Pos(), invocant, args.(*node.ListNode)) }