func()

in internal/compile/compile.go [1047:1240]


func (fcomp *fcomp) stmt(stmt syntax.Stmt) {
	switch stmt := stmt.(type) {
	case *syntax.ExprStmt:
		if _, ok := stmt.X.(*syntax.Literal); ok {
			// Opt: don't compile doc comments only to pop them.
			return
		}
		fcomp.expr(stmt.X)
		fcomp.emit(POP)

	case *syntax.BranchStmt:
		// Resolver invariant: break/continue appear only within loops.
		switch stmt.Token {
		case syntax.PASS:
			// no-op
		case syntax.BREAK:
			b := fcomp.loops[len(fcomp.loops)-1].break_
			fcomp.jump(b)
			fcomp.block = fcomp.newBlock() // dead code
		case syntax.CONTINUE:
			b := fcomp.loops[len(fcomp.loops)-1].continue_
			fcomp.jump(b)
			fcomp.block = fcomp.newBlock() // dead code
		}

	case *syntax.IfStmt:
		// Keep consistent with CondExpr.
		t := fcomp.newBlock()
		f := fcomp.newBlock()
		done := fcomp.newBlock()

		fcomp.ifelse(stmt.Cond, t, f)

		fcomp.block = t
		fcomp.stmts(stmt.True)
		fcomp.jump(done)

		fcomp.block = f
		fcomp.stmts(stmt.False)
		fcomp.jump(done)

		fcomp.block = done

	case *syntax.AssignStmt:
		switch stmt.Op {
		case syntax.EQ:
			// simple assignment: x = y
			fcomp.expr(stmt.RHS)
			fcomp.assign(stmt.OpPos, stmt.LHS)

		case syntax.PLUS_EQ,
			syntax.MINUS_EQ,
			syntax.STAR_EQ,
			syntax.SLASH_EQ,
			syntax.SLASHSLASH_EQ,
			syntax.PERCENT_EQ,
			syntax.AMP_EQ,
			syntax.PIPE_EQ,
			syntax.CIRCUMFLEX_EQ,
			syntax.LTLT_EQ,
			syntax.GTGT_EQ:
			// augmented assignment: x += y

			var set func()

			// Evaluate "address" of x exactly once to avoid duplicate side-effects.
			switch lhs := unparen(stmt.LHS).(type) {
			case *syntax.Ident:
				// x = ...
				fcomp.lookup(lhs)
				set = func() {
					fcomp.set(lhs)
				}

			case *syntax.IndexExpr:
				// x[y] = ...
				fcomp.expr(lhs.X)
				fcomp.expr(lhs.Y)
				fcomp.emit(DUP2)
				fcomp.setPos(lhs.Lbrack)
				fcomp.emit(INDEX)
				set = func() {
					fcomp.setPos(lhs.Lbrack)
					fcomp.emit(SETINDEX)
				}

			case *syntax.DotExpr:
				// x.f = ...
				fcomp.expr(lhs.X)
				fcomp.emit(DUP)
				name := fcomp.pcomp.nameIndex(lhs.Name.Name)
				fcomp.setPos(lhs.Dot)
				fcomp.emit1(ATTR, name)
				set = func() {
					fcomp.setPos(lhs.Dot)
					fcomp.emit1(SETFIELD, name)
				}

			default:
				panic(lhs)
			}

			fcomp.expr(stmt.RHS)

			// In-place x+=y and x|=y have special semantics:
			// the resulting x aliases the original x.
			switch stmt.Op {
			case syntax.PLUS_EQ:
				fcomp.setPos(stmt.OpPos)
				fcomp.emit(INPLACE_ADD)
			case syntax.PIPE_EQ:
				fcomp.setPos(stmt.OpPos)
				fcomp.emit(INPLACE_PIPE)
			default:
				fcomp.binop(stmt.OpPos, stmt.Op-syntax.PLUS_EQ+syntax.PLUS)
			}
			set()
		}

	case *syntax.DefStmt:
		fcomp.function(stmt.Function.(*resolve.Function))
		fcomp.set(stmt.Name)

	case *syntax.ForStmt:
		// Keep consistent with ForClause.
		head := fcomp.newBlock()
		body := fcomp.newBlock()
		tail := fcomp.newBlock()

		fcomp.expr(stmt.X)
		fcomp.setPos(stmt.For)
		fcomp.emit(ITERPUSH)
		fcomp.jump(head)

		fcomp.block = head
		fcomp.condjump(ITERJMP, tail, body)

		fcomp.block = body
		fcomp.assign(stmt.For, stmt.Vars)
		fcomp.loops = append(fcomp.loops, loop{break_: tail, continue_: head})
		fcomp.stmts(stmt.Body)
		fcomp.loops = fcomp.loops[:len(fcomp.loops)-1]
		fcomp.jump(head)

		fcomp.block = tail
		fcomp.emit(ITERPOP)

	case *syntax.WhileStmt:
		head := fcomp.newBlock()
		body := fcomp.newBlock()
		done := fcomp.newBlock()

		fcomp.jump(head)
		fcomp.block = head
		fcomp.ifelse(stmt.Cond, body, done)

		fcomp.block = body
		fcomp.loops = append(fcomp.loops, loop{break_: done, continue_: head})
		fcomp.stmts(stmt.Body)
		fcomp.loops = fcomp.loops[:len(fcomp.loops)-1]
		fcomp.jump(head)

		fcomp.block = done

	case *syntax.ReturnStmt:
		if stmt.Result != nil {
			fcomp.expr(stmt.Result)
		} else {
			fcomp.emit(NONE)
		}
		fcomp.emit(RETURN)
		fcomp.block = fcomp.newBlock() // dead code

	case *syntax.LoadStmt:
		for i := range stmt.From {
			fcomp.string(stmt.From[i].Name)
		}
		module := stmt.Module.Value.(string)
		fcomp.pcomp.prog.Loads = append(fcomp.pcomp.prog.Loads, Binding{
			Name: module,
			Pos:  stmt.Module.TokenPos,
		})
		fcomp.string(module)
		fcomp.setPos(stmt.Load)
		fcomp.emit1(LOAD, uint32(len(stmt.From)))
		for i := range stmt.To {
			fcomp.set(stmt.To[len(stmt.To)-1-i])
		}

	default:
		start, _ := stmt.Span()
		log.Panicf("%s: exec: unexpected statement %T", start, stmt)
	}
}