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)
}
}