diff --git a/compiler/ast/eval.go b/compiler/ast/eval.go index 52b57e8b..f731fab5 100644 --- a/compiler/ast/eval.go +++ b/compiler/ast/eval.go @@ -211,6 +211,60 @@ func (ast *Call) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) ( // Eval implements the compiler.ast.AST.Eval. func (ast *ArrayCast) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) ( ssa.Value, bool, error) { + + typeInfo, err := ast.TypeInfo.Resolve(env, ctx, gen) + if err != nil { + return ssa.Undefined, false, err + } + if typeInfo.Type != types.TArray { + return ssa.Undefined, false, + ctx.Errorf(ast.Expr, "array cast to non-array type %v", typeInfo) + } + + cv, ok, err := ast.Expr.Eval(env, ctx, gen) + if err != nil { + return ssa.Undefined, false, err + } + if !ok { + return ssa.Undefined, false, nil + } + + switch cv.Type.Type { + case types.TString: + if cv.Type.Bits%8 != 0 { + return ssa.Undefined, false, + ctx.Errorf(ast.Expr, "invalid string length %v", cv.Type.Bits) + } + chars := cv.Type.Bits / 8 + et := typeInfo.ElementType + if et.Bits != 8 || et.Type != types.TUint { + return ssa.Undefined, false, + ctx.Errorf(ast.Expr, "cast from %v to %v", + cv.Type, ast.TypeInfo) + } + + if typeInfo.Concrete() { + if typeInfo.ArraySize != chars || typeInfo.Bits != cv.Type.Bits { + return ssa.Undefined, false, + ctx.Errorf(ast.Expr, "cast from %v to %v", + cv.Type, ast.TypeInfo) + } + } else { + typeInfo.Bits = cv.Type.Bits + typeInfo.ArraySize = chars + typeInfo.SetConcrete(true) + } + cast := cv + cast.Type = typeInfo + if cv.HashCode() != cast.HashCode() { + panic("const array cast changes value HashCode") + } + if !cv.Equal(&cast) { + panic("const array cast changes value equality") + } + return cast, true, nil + } + return ssa.Undefined, false, nil } diff --git a/compiler/tests/const_cast_bytearr_string.mpcl b/compiler/tests/const_cast_bytearr_string.mpcl new file mode 100644 index 00000000..7a128a6d --- /dev/null +++ b/compiler/tests/const_cast_bytearr_string.mpcl @@ -0,0 +1,11 @@ +// -*- go -*- + +package main + +// 0x48656c6c6f2c20776f726c6421 + +// @Test 42 1 = 0x21646c726f77202c6f6c6c6548 +func main(a []byte, b int) []byte { + ret := []byte("Hello, world!") + return ret +} diff --git a/compiler/tests/const_cast_string_bytearr.mpcl b/compiler/tests/const_cast_string_bytearr.mpcl new file mode 100644 index 00000000..1b6bbdf2 --- /dev/null +++ b/compiler/tests/const_cast_string_bytearr.mpcl @@ -0,0 +1,13 @@ +// -*- go -*- + +package main + +// @Test 42 1 = 0x21646c726f77202c6f6c6c6548 +func main(a []byte, b int) string { + val := []byte{ + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, + 0x6f, 0x72, 0x6c, 0x64, 0x21, + } + ret := string(val) + return ret +}