blob: 2dffd932c99fc2ff3e7d8c485c68ce410fd5a03a [file] [log] [blame]
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package resolver
import (
"android.googlesource.com/platform/tools/gpu/api/ast"
"android.googlesource.com/platform/tools/gpu/api/semantic"
)
func unaryOp(ctx *context, in *ast.UnaryOp) *semantic.UnaryOp {
out := &semantic.UnaryOp{AST: in}
out.Operator = in.Operator
out.Expression = expression(ctx, in.Expression)
et := out.Expression.ExpressionType()
switch out.Operator {
case ast.OpNot:
out.Type = semantic.BoolType
if !equal(et, semantic.BoolType) {
ctx.errorf(in, "operator %s applied to non bool type %s", out.Operator, typename(et))
}
default:
ctx.icef(in, "unhandled unary operator %s", out.Operator)
}
ctx.mappings[in] = out
return out
}
func binaryOp(ctx *context, in *ast.BinaryOp) semantic.Expression {
var lhs semantic.Expression
var rhs semantic.Expression
switch in.LHS.(type) {
case *ast.Number, *ast.Null, *ast.Definition:
// leave these to be inferred after the rhs is known
default:
lhs = expression(ctx, in.LHS)
}
if in.RHS == nil {
if lhs == nil {
// lhs was deferred, but no rhs is available
lhs = expression(ctx, in.LHS)
}
} else if lhs != nil {
ctx.with(lhs.ExpressionType(), func() {
// allow us to infer rhs type from lhs
rhs = expression(ctx, in.RHS)
})
} else {
// lhs was deferred, do the rhs first
rhs = expression(ctx, in.RHS)
ctx.with(rhs.ExpressionType(), func() {
// allow us to infer lhs type from rhs
lhs = expression(ctx, in.LHS)
})
}
lt := lhs.ExpressionType()
rt := semantic.Type(semantic.VoidType)
if rhs != nil {
rt = rhs.ExpressionType()
}
var out semantic.Expression
switch in.Operator {
case ast.OpIn:
switch rt := rt.(type) {
case *semantic.Map:
if !comparable(lt, rt.KeyType) {
ctx.errorf(in, "%s with type %s, but map key type is %s", in.Operator, typename(lt), typename(rt.KeyType))
}
out = &semantic.MapContains{AST: in, Map: rhs, Key: lhs}
case *semantic.Enum:
if !equal(lt, rt) {
ctx.errorf(in, "enum bittest on %s with %s is not allowed", typename(lt), typename(rt))
}
out = &semantic.BitTest{AST: in, Bitfield: rhs, Bits: lhs}
default:
ctx.errorf(in, "%s only allowed on maps, not %s", in.Operator, typename(rt))
return invalid{}
}
case ast.OpEQ, ast.OpGT, ast.OpLT, ast.OpGE, ast.OpLE, ast.OpNE:
if !comparable(lt, rt) {
ctx.errorf(in, "comparison %s %s %s not allowed", typename(lt), in.Operator, typename(rt))
}
out = &semantic.BinaryOp{AST: in, LHS: lhs, RHS: rhs, Type: semantic.BoolType, Operator: in.Operator}
case ast.OpOr, ast.OpAnd:
if !equal(lt, semantic.BoolType) {
ctx.errorf(in, "lhs of %s is %s not boolean", in.Operator, typename(lt))
}
if !equal(rt, semantic.BoolType) {
ctx.errorf(in, "rhs of %s is %s not boolean", in.Operator, typename(rt))
}
out = &semantic.BinaryOp{AST: in, LHS: lhs, RHS: rhs, Type: semantic.BoolType, Operator: in.Operator}
case ast.OpBitwiseAnd, ast.OpBitwiseOr:
_, ltEnum := ctx.findType(in, typename(lt)).(*semantic.Enum)
if !((ltEnum || isNumber(lt)) && equal(lt, rt)) {
ctx.errorf(in, "incompatible types for bitwise maths %s %s %s", typename(lt), in.Operator, typename(rt))
}
out = &semantic.BinaryOp{AST: in, LHS: lhs, RHS: rhs, Type: lt, Operator: in.Operator}
case ast.OpPlus, ast.OpMinus, ast.OpMultiply, ast.OpDivide:
if !equal(lt, rt) {
ctx.errorf(in, "incompatible types for maths %s %s %s", typename(lt), in.Operator, typename(rt))
}
out = &semantic.BinaryOp{AST: in, LHS: lhs, RHS: rhs, Type: lt, Operator: in.Operator}
case ast.OpRange:
if !equal(lt, rt) {
ctx.errorf(in, "range %s %s %s not allowed", typename(lt), in.Operator, typename(rt))
}
out = &semantic.BinaryOp{AST: in, LHS: lhs, RHS: rhs, Type: lt, Operator: in.Operator}
case ast.OpSlice:
out = &semantic.BinaryOp{AST: in, LHS: lhs, RHS: rhs, Type: lt, Operator: in.Operator}
default:
ctx.icef(in, "unknown binary operator %s", in.Operator)
return invalid{}
}
ctx.mappings[in] = out
return out
}