func()

in internal/compile/compile.go [1291:1456]


func (fcomp *fcomp) expr(e syntax.Expr) {
	switch e := e.(type) {
	case *syntax.ParenExpr:
		fcomp.expr(e.X)

	case *syntax.Ident:
		fcomp.lookup(e)

	case *syntax.Literal:
		// e.Value is int64, float64, *bigInt, string
		v := e.Value
		if e.Token == syntax.BYTES {
			v = Bytes(v.(string))
		}
		fcomp.emit1(CONSTANT, fcomp.pcomp.constantIndex(v))

	case *syntax.ListExpr:
		for _, x := range e.List {
			fcomp.expr(x)
		}
		fcomp.emit1(MAKELIST, uint32(len(e.List)))

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

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

		fcomp.block = t
		fcomp.expr(e.True)
		fcomp.jump(done)

		fcomp.block = f
		fcomp.expr(e.False)
		fcomp.jump(done)

		fcomp.block = done

	case *syntax.IndexExpr:
		fcomp.expr(e.X)
		fcomp.expr(e.Y)
		fcomp.setPos(e.Lbrack)
		fcomp.emit(INDEX)

	case *syntax.SliceExpr:
		fcomp.setPos(e.Lbrack)
		fcomp.expr(e.X)
		if e.Lo != nil {
			fcomp.expr(e.Lo)
		} else {
			fcomp.emit(NONE)
		}
		if e.Hi != nil {
			fcomp.expr(e.Hi)
		} else {
			fcomp.emit(NONE)
		}
		if e.Step != nil {
			fcomp.expr(e.Step)
		} else {
			fcomp.emit(NONE)
		}
		fcomp.emit(SLICE)

	case *syntax.Comprehension:
		if e.Curly {
			fcomp.emit(MAKEDICT)
		} else {
			fcomp.emit1(MAKELIST, 0)
		}
		fcomp.comprehension(e, 0)

	case *syntax.TupleExpr:
		fcomp.tuple(e.List)

	case *syntax.DictExpr:
		fcomp.emit(MAKEDICT)
		for _, entry := range e.List {
			entry := entry.(*syntax.DictEntry)
			fcomp.emit(DUP)
			fcomp.expr(entry.Key)
			fcomp.expr(entry.Value)
			fcomp.setPos(entry.Colon)
			fcomp.emit(SETDICTUNIQ)
		}

	case *syntax.UnaryExpr:
		fcomp.expr(e.X)
		fcomp.setPos(e.OpPos)
		switch e.Op {
		case syntax.MINUS:
			fcomp.emit(UMINUS)
		case syntax.PLUS:
			fcomp.emit(UPLUS)
		case syntax.NOT:
			fcomp.emit(NOT)
		case syntax.TILDE:
			fcomp.emit(TILDE)
		default:
			log.Panicf("%s: unexpected unary op: %s", e.OpPos, e.Op)
		}

	case *syntax.BinaryExpr:
		switch e.Op {
		// short-circuit operators
		// TODO(adonovan): use ifelse to simplify conditions.
		case syntax.OR:
			// x or y  =>  if x then x else y
			done := fcomp.newBlock()
			y := fcomp.newBlock()

			fcomp.expr(e.X)
			fcomp.emit(DUP)
			fcomp.condjump(CJMP, done, y)

			fcomp.block = y
			fcomp.emit(POP) // discard X
			fcomp.expr(e.Y)
			fcomp.jump(done)

			fcomp.block = done

		case syntax.AND:
			// x and y  =>  if x then y else x
			done := fcomp.newBlock()
			y := fcomp.newBlock()

			fcomp.expr(e.X)
			fcomp.emit(DUP)
			fcomp.condjump(CJMP, y, done)

			fcomp.block = y
			fcomp.emit(POP) // discard X
			fcomp.expr(e.Y)
			fcomp.jump(done)

			fcomp.block = done

		case syntax.PLUS:
			fcomp.plus(e)

		default:
			// all other strict binary operator (includes comparisons)
			fcomp.expr(e.X)
			fcomp.expr(e.Y)
			fcomp.binop(e.OpPos, e.Op)
		}

	case *syntax.DotExpr:
		fcomp.expr(e.X)
		fcomp.setPos(e.Dot)
		fcomp.emit1(ATTR, fcomp.pcomp.nameIndex(e.Name.Name))

	case *syntax.CallExpr:
		fcomp.call(e)

	case *syntax.LambdaExpr:
		fcomp.function(e.Function.(*resolve.Function))

	default:
		start, _ := e.Span()
		log.Panicf("%s: unexpected expr %T", start, e)
	}
}