diff --git a/emacs/actorscript-mode.el b/emacs/actorscript-mode.el index 39ded3f1ab3..3e87ae6ffa3 100644 --- a/emacs/actorscript-mode.el +++ b/emacs/actorscript-mode.el @@ -13,6 +13,14 @@ "Bool" "Nat" "Int" + "Int8" + "Int16" + "Int32" + "Int64" + "Nat8" + "Nat16" + "Nat32" + "Nat64" "Word8" "Word16" "Word32" diff --git a/src/as_frontend/arrange.ml b/src/as_frontend/arrange.ml index 5c28fbe5d37..98d2e2cdca6 100644 --- a/src/as_frontend/arrange.ml +++ b/src/as_frontend/arrange.ml @@ -75,7 +75,15 @@ and lit (l:lit) = match l with | BoolLit true -> "BoolLit" $$ [ Atom "true" ] | BoolLit false -> "BoolLit" $$ [ Atom "false" ] | NatLit n -> "NatLit" $$ [ Atom (Value.Nat.to_pretty_string n) ] + | Nat8Lit n -> "Nat8Lit" $$ [ Atom (Value.Nat8.to_pretty_string n) ] + | Nat16Lit n -> "Nat16Lit" $$ [ Atom (Value.Nat16.to_pretty_string n) ] + | Nat32Lit n -> "Nat32Lit" $$ [ Atom (Value.Nat32.to_pretty_string n) ] + | Nat64Lit n -> "Nat64Lit" $$ [ Atom (Value.Nat64.to_pretty_string n) ] | IntLit i -> "IntLit" $$ [ Atom (Value.Int.to_pretty_string i) ] + | Int8Lit i -> "Int8Lit" $$ [ Atom (Value.Int_8.to_pretty_string i) ] + | Int16Lit i -> "Int16Lit" $$ [ Atom (Value.Int_16.to_pretty_string i) ] + | Int32Lit i -> "Int32Lit" $$ [ Atom (Value.Int_32.to_pretty_string i) ] + | Int64Lit i -> "Int64Lit" $$ [ Atom (Value.Int_64.to_pretty_string i) ] | Word8Lit w -> "Word8Lit" $$ [ Atom (Value.Word8.to_pretty_string w) ] | Word16Lit w -> "Word16Lit" $$ [ Atom (Value.Word16.to_pretty_string w) ] | Word32Lit w -> "Word32Lit" $$ [ Atom (Value.Word32.to_pretty_string w) ] diff --git a/src/as_frontend/coverage.ml b/src/as_frontend/coverage.ml index 0f444651892..d5b4efd5aeb 100644 --- a/src/as_frontend/coverage.ml +++ b/src/as_frontend/coverage.ml @@ -48,7 +48,15 @@ let value_of_lit = function | NullLit -> V.Null | BoolLit b -> V.Bool b | NatLit n -> V.Int n + | Nat8Lit w -> V.Nat8 w + | Nat16Lit w -> V.Nat16 w + | Nat32Lit w -> V.Nat32 w + | Nat64Lit w -> V.Nat64 w | IntLit i -> V.Int i + | Int8Lit w -> V.Int8 w + | Int16Lit w -> V.Int16 w + | Int32Lit w -> V.Int32 w + | Int64Lit w -> V.Int64 w | Word8Lit w -> V.Word8 w | Word16Lit w -> V.Word16 w | Word32Lit w -> V.Word32 w diff --git a/src/as_frontend/syntax.ml b/src/as_frontend/syntax.ml index b87fdf77d6f..8567860b45b 100644 --- a/src/as_frontend/syntax.ml +++ b/src/as_frontend/syntax.ml @@ -61,7 +61,15 @@ type lit = | NullLit | BoolLit of bool | NatLit of Value.Nat.t + | Nat8Lit of Value.Nat8.t + | Nat16Lit of Value.Nat16.t + | Nat32Lit of Value.Nat32.t + | Nat64Lit of Value.Nat64.t | IntLit of Value.Int.t + | Int8Lit of Value.Int_8.t + | Int16Lit of Value.Int_16.t + | Int32Lit of Value.Int_32.t + | Int64Lit of Value.Int_64.t | Word8Lit of Value.Word8.t | Word16Lit of Value.Word16.t | Word32Lit of Value.Word32.t @@ -196,6 +204,14 @@ let string_of_lit = function | BoolLit true -> "true" | IntLit n | NatLit n -> Value.Int.to_pretty_string n + | Int8Lit n -> Value.Int_8.to_pretty_string n + | Int16Lit n -> Value.Int_16.to_pretty_string n + | Int32Lit n -> Value.Int_32.to_pretty_string n + | Int64Lit n -> Value.Int_64.to_pretty_string n + | Nat8Lit n -> Value.Nat8.to_pretty_string n + | Nat16Lit n -> Value.Nat16.to_pretty_string n + | Nat32Lit n -> Value.Nat32.to_pretty_string n + | Nat64Lit n -> Value.Nat64.to_pretty_string n | Word8Lit n -> Value.Word8.to_pretty_string n | Word16Lit n -> Value.Word16.to_pretty_string n | Word32Lit n -> Value.Word32.to_pretty_string n diff --git a/src/as_frontend/typing.ml b/src/as_frontend/typing.ml index 14a7066dafc..b83219f4368 100644 --- a/src/as_frontend/typing.ml +++ b/src/as_frontend/typing.ml @@ -302,7 +302,15 @@ let check_lit_val env t of_string at s = (T.string_of_typ (T.Prim t)) let check_nat env = check_lit_val env T.Nat Value.Nat.of_string +let check_nat8 env = check_lit_val env T.Nat8 Value.Nat8.of_string +let check_nat16 env = check_lit_val env T.Nat16 Value.Nat16.of_string +let check_nat32 env = check_lit_val env T.Nat32 Value.Nat32.of_string +let check_nat64 env = check_lit_val env T.Nat64 Value.Nat64.of_string let check_int env = check_lit_val env T.Int Value.Int.of_string +let check_int8 env = check_lit_val env T.Int8 Value.Int_8.of_string +let check_int16 env = check_lit_val env T.Int16 Value.Int_16.of_string +let check_int32 env = check_lit_val env T.Int32 Value.Int_32.of_string +let check_int64 env = check_lit_val env T.Int64 Value.Int_64.of_string let check_word8 env = check_lit_val env T.Word8 Value.Word8.of_string_u let check_word16 env = check_lit_val env T.Word16 Value.Word16.of_string_u let check_word32 env = check_lit_val env T.Word32 Value.Word32.of_string_u @@ -315,7 +323,15 @@ let infer_lit env lit at : T.prim = | NullLit -> T.Null | BoolLit _ -> T.Bool | NatLit _ -> T.Nat + | Nat8Lit _ -> T.Nat8 + | Nat16Lit _ -> T.Nat16 + | Nat32Lit _ -> T.Nat32 + | Nat64Lit _ -> T.Nat64 | IntLit _ -> T.Int + | Int8Lit _ -> T.Int8 + | Int16Lit _ -> T.Int16 + | Int32Lit _ -> T.Int32 + | Int64Lit _ -> T.Int64 | Word8Lit _ -> T.Word8 | Word16Lit _ -> T.Word16 | Word32Lit _ -> T.Word32 @@ -340,8 +356,24 @@ let check_lit env t lit at = | T.Opt _, NullLit -> () | T.Prim T.Nat, PreLit (s, T.Nat) -> lit := NatLit (check_nat env at s) + | T.Prim T.Nat8, PreLit (s, T.Nat) -> + lit := Nat8Lit (check_nat8 env at s) + | T.Prim T.Nat16, PreLit (s, T.Nat) -> + lit := Nat16Lit (check_nat16 env at s) + | T.Prim T.Nat32, PreLit (s, T.Nat) -> + lit := Nat32Lit (check_nat32 env at s) + | T.Prim T.Nat64, PreLit (s, T.Nat) -> + lit := Nat64Lit (check_nat64 env at s) | T.Prim T.Int, PreLit (s, (T.Nat | T.Int)) -> lit := IntLit (check_int env at s) + | T.Prim T.Int8, PreLit (s, (T.Nat | T.Int)) -> + lit := Int8Lit (check_int8 env at s) + | T.Prim T.Int16, PreLit (s, (T.Nat | T.Int)) -> + lit := Int16Lit (check_int16 env at s) + | T.Prim T.Int32, PreLit (s, (T.Nat | T.Int)) -> + lit := Int32Lit (check_int32 env at s) + | T.Prim T.Int64, PreLit (s, (T.Nat | T.Int)) -> + lit := Int64Lit (check_int64 env at s) | T.Prim T.Word8, PreLit (s, (T.Nat | T.Int)) -> lit := Word8Lit (check_word8 env at s) | T.Prim T.Word16, PreLit (s, (T.Nat | T.Int)) -> @@ -394,6 +426,11 @@ and infer_exp' f env exp : T.typ = end; t' +and special_unop_typing = let open T in + function + | Prim Nat -> Prim Int + | t -> t + and infer_exp'' env exp : T.typ = match exp.it with | PrimE _ -> @@ -411,7 +448,7 @@ and infer_exp'' env exp : T.typ = | UnE (ot, op, exp1) -> let t1 = infer_exp_promote env exp1 in (* Special case for subtyping *) - let t = if t1 = T.Prim T.Nat then T.Prim T.Int else t1 in + let t = special_unop_typing t1 in if not env.pre then begin assert (!ot = Type.Pre); if not (Operator.has_unop t op) then @@ -858,7 +895,7 @@ and infer_pat' env pat : T.typ * Scope.val_env = | SignP (op, lit) -> let t1 = T.Prim (infer_lit env lit pat.at) in (* Special case for subtyping *) - let t = if t1 = T.Prim T.Nat then T.Prim T.Int else t1 in + let t = special_unop_typing t1 in if not (Operator.has_unop t op) then local_error env pat.at "operator is not defined for operand type\n %s" (T.string_of_typ_expand t); diff --git a/src/as_ir/arrange_ir.ml b/src/as_ir/arrange_ir.ml index e338a6e6b1f..49e9b52a743 100644 --- a/src/as_ir/arrange_ir.ml +++ b/src/as_ir/arrange_ir.ml @@ -73,7 +73,15 @@ and lit (l:lit) = match l with | BoolLit true -> "BoolLit" $$ [ Atom "true" ] | BoolLit false -> "BoolLit" $$ [ Atom "false" ] | NatLit n -> "NatLit" $$ [ Atom (Value.Nat.to_pretty_string n) ] + | Nat8Lit w -> "Nat8Lit" $$ [ Atom (Value.Nat8.to_pretty_string w) ] + | Nat16Lit w -> "Nat16Lit" $$ [ Atom (Value.Nat16.to_pretty_string w) ] + | Nat32Lit w -> "Nat32Lit" $$ [ Atom (Value.Nat32.to_pretty_string w) ] + | Nat64Lit w -> "Nat64Lit" $$ [ Atom (Value.Nat64.to_pretty_string w) ] | IntLit i -> "IntLit" $$ [ Atom (Value.Int.to_pretty_string i) ] + | Int8Lit w -> "Int8Lit" $$ [ Atom (Value.Int_8.to_pretty_string w) ] + | Int16Lit w -> "Int16Lit" $$ [ Atom (Value.Int_16.to_pretty_string w) ] + | Int32Lit w -> "Int32Lit" $$ [ Atom (Value.Int_32.to_pretty_string w) ] + | Int64Lit w -> "Int64Lit" $$ [ Atom (Value.Int_64.to_pretty_string w) ] | Word8Lit w -> "Word8Lit" $$ [ Atom (Value.Word8.to_pretty_string w) ] | Word16Lit w -> "Word16Lit" $$ [ Atom (Value.Word16.to_pretty_string w) ] | Word32Lit w -> "Word32Lit" $$ [ Atom (Value.Word32.to_pretty_string w) ] diff --git a/src/as_ir/check_ir.ml b/src/as_ir/check_ir.ml index c9d1eefc39d..a213349bc6a 100644 --- a/src/as_ir/check_ir.ml +++ b/src/as_ir/check_ir.ml @@ -250,7 +250,15 @@ let type_lit env lit at : T.prim = | NullLit -> T.Null | BoolLit _ -> T.Bool | NatLit _ -> T.Nat + | Nat8Lit _ -> T.Nat8 + | Nat16Lit _ -> T.Nat16 + | Nat32Lit _ -> T.Nat32 + | Nat64Lit _ -> T.Nat64 | IntLit _ -> T.Int + | Int8Lit _ -> T.Int8 + | Int16Lit _ -> T.Int16 + | Int32Lit _ -> T.Int32 + | Int64Lit _ -> T.Int64 | Word8Lit _ -> T.Word8 | Word16Lit _ -> T.Word16 | Word32Lit _ -> T.Word32 diff --git a/src/as_ir/ir.ml b/src/as_ir/ir.ml index e04d743b318..05131e9e193 100644 --- a/src/as_ir/ir.ml +++ b/src/as_ir/ir.ml @@ -9,7 +9,15 @@ type lit = | NullLit | BoolLit of bool | NatLit of Value.Nat.t + | Nat8Lit of Value.Nat8.t + | Nat16Lit of Value.Nat16.t + | Nat32Lit of Value.Nat32.t + | Nat64Lit of Value.Nat64.t | IntLit of Value.Int.t + | Int8Lit of Value.Int_8.t + | Int16Lit of Value.Int_16.t + | Int32Lit of Value.Int_32.t + | Int64Lit of Value.Int_64.t | Word8Lit of Value.Word8.t | Word16Lit of Value.Word16.t | Word32Lit of Value.Word32.t @@ -110,6 +118,14 @@ let string_of_lit = function | BoolLit true -> "true" | IntLit n | NatLit n -> Value.Int.to_pretty_string n + | Int8Lit n -> Value.Int_8.to_pretty_string n + | Int16Lit n -> Value.Int_16.to_pretty_string n + | Int32Lit n -> Value.Int_32.to_pretty_string n + | Int64Lit n -> Value.Int_64.to_pretty_string n + | Nat8Lit n -> Value.Nat8.to_pretty_string n + | Nat16Lit n -> Value.Nat16.to_pretty_string n + | Nat32Lit n -> Value.Nat32.to_pretty_string n + | Nat64Lit n -> Value.Nat64.to_pretty_string n | Word8Lit n -> Value.Word8.to_pretty_string n | Word16Lit n -> Value.Word16.to_pretty_string n | Word32Lit n -> Value.Word32.to_pretty_string n diff --git a/src/as_types/arrange_type.ml b/src/as_types/arrange_type.ml index 1a9ea33babb..51c180ce303 100644 --- a/src/as_types/arrange_type.ml +++ b/src/as_types/arrange_type.ml @@ -20,7 +20,15 @@ let prim p = match p with | Null -> Atom "Null" | Bool -> Atom "Bool" | Nat -> Atom "Nat" + | Nat8 -> Atom "Nat8" + | Nat16 -> Atom "Nat16" + | Nat32 -> Atom "Nat32" + | Nat64 -> Atom "Nat64" | Int -> Atom "Int" + | Int8 -> Atom "Int8" + | Int16 -> Atom "Int16" + | Int32 -> Atom "Int32" + | Int64 -> Atom "Int64" | Word8 -> Atom "Word8" | Word16 -> Atom "Word16" | Word32 -> Atom "Word32" diff --git a/src/as_types/type.ml b/src/as_types/type.ml index 662031c2787..8ca00731cb7 100644 --- a/src/as_types/type.ml +++ b/src/as_types/type.ml @@ -12,7 +12,15 @@ type prim = | Null | Bool | Nat + | Nat8 + | Nat16 + | Nat32 + | Nat64 | Int + | Int8 + | Int16 + | Int32 + | Int64 | Word8 | Word16 | Word32 @@ -72,7 +80,15 @@ let prim = function | "Null" -> Null | "Bool" -> Bool | "Nat" -> Nat + | "Nat8" -> Nat8 + | "Nat16" -> Nat16 + | "Nat32" -> Nat32 + | "Nat64" -> Nat64 | "Int" -> Int + | "Int8" -> Int8 + | "Int16" -> Int16 + | "Int32" -> Int32 + | "Int64" -> Int64 | "Word8" -> Word8 | "Word16" -> Word16 | "Word32" -> Word32 @@ -399,9 +415,9 @@ let rec span = function | Prim Null -> Some 1 | Prim Bool -> Some 2 | Prim (Nat | Int | Float | Text) -> None - | Prim Word8 -> Some 0x100 - | Prim Word16 -> Some 0x10000 - | Prim (Word32 | Word64 | Char) -> None (* for all practical purpuses *) + | Prim (Nat8 | Int8 | Word8) -> Some 0x100 + | Prim (Nat16 | Int16 | Word16) -> Some 0x10000 + | Prim (Nat32 | Int32 | Word32 | Nat64 | Int64 | Word64 | Char) -> None (* for all practical purposes *) | Obj _ | Tup _ | Async _ -> Some 1 | Variant fs -> Some (List.length fs) | Array _ | Func _ | Shared | Any -> None @@ -785,7 +801,15 @@ let string_of_prim = function | Null -> "Null" | Bool -> "Bool" | Nat -> "Nat" + | Nat8 -> "Nat8" + | Nat16 -> "Nat16" + | Nat32 -> "Nat32" + | Nat64 -> "Nat64" | Int -> "Int" + | Int8 -> "Int8" + | Int16 -> "Int16" + | Int32 -> "Int32" + | Int64 -> "Int64" | Float -> "Float" | Word8 -> "Word8" | Word16 -> "Word16" diff --git a/src/as_types/type.mli b/src/as_types/type.mli index 3835d0eed5d..4316a8b11ce 100644 --- a/src/as_types/type.mli +++ b/src/as_types/type.mli @@ -12,7 +12,15 @@ type prim = | Null | Bool | Nat + | Nat8 + | Nat16 + | Nat32 + | Nat64 | Int + | Int8 + | Int16 + | Int32 + | Int64 | Word8 | Word16 | Word32 diff --git a/src/as_values/operator.ml b/src/as_values/operator.ml index 1e183741407..57d2a324ab7 100644 --- a/src/as_values/operator.ml +++ b/src/as_values/operator.ml @@ -39,25 +39,35 @@ let impossible _ = raise (Invalid_argument "impossible") (* Unary operators *) -let word_unop fword8 fword16 fword32 fword64 = function +let word_unop (fword8, fword16, fword32, fword64) = function | T.Word8 -> fun v -> Word8 (fword8 (as_word8 v)) | T.Word16 -> fun v -> Word16 (fword16 (as_word16 v)) | T.Word32 -> fun v -> Word32 (fword32 (as_word32 v)) | T.Word64 -> fun v -> Word64 (fword64 (as_word64 v)) | _ -> raise (Invalid_argument "unop") -let num_unop fint fword8 fword16 fword32 fword64 ffloat = function +let num_unop fint (fint8, fint16, fint32, fint64) wordops ffloat = function | T.Int -> fun v -> Int (fint (as_int v)) + | T.Int8 -> fun v -> Int8 (fint8 (as_int8 v)) + | T.Int16 -> fun v -> Int16 (fint16 (as_int16 v)) + | T.Int32 -> fun v -> Int32 (fint32 (as_int32 v)) + | T.Int64 -> fun v -> Int64 (fint64 (as_int64 v)) | T.Float -> fun v -> Float (ffloat (as_float v)) - | t -> word_unop fword8 fword16 fword32 fword64 t + | t -> word_unop wordops t let unop t op = match t with | T.Prim p -> (match op with - | PosOp -> let id v = v in num_unop id id id id id id p - | NegOp -> num_unop Int.neg Word8.neg Word16.neg Word32.neg Word64.neg Float.neg p - | NotOp -> word_unop Word8.not Word16.not Word32.not Word64.not p + | PosOp -> let id v = v in num_unop id (id, id, id, id) (id, id, id, id) id p + | NegOp -> + num_unop + Int.neg + (Int_8.neg, Int_16.neg, Int_32.neg, Int_64.neg) + (Word8.neg, Word16.neg, Word32.neg, Word64.neg) + Float.neg + p + | NotOp -> word_unop (Word8.not, Word16.not, Word32.not, Word64.not) p ) | T.Non -> impossible | _ -> raise (Invalid_argument "unop") @@ -108,39 +118,43 @@ let binop t op = (* Relational operators *) -let word_relop fword8 fword16 fword32 fword64 = function +let word_relop (fword8, fword16, fword32, fword64) = function | T.Word8 -> fun v1 v2 -> Bool (fword8 (as_word8 v1) (as_word8 v2)) | T.Word16 -> fun v1 v2 -> Bool (fword16 (as_word16 v1) (as_word16 v2)) | T.Word32 -> fun v1 v2 -> Bool (fword32 (as_word32 v1) (as_word32 v2)) | T.Word64 -> fun v1 v2 -> Bool (fword64 (as_word64 v1) (as_word64 v2)) | _ -> raise (Invalid_argument "relop") -let num_relop fnat fint fword8 fword16 fword32 fword64 ffloat = function +let num_relop fnat fint (fint8, fint16, fint32, fint64) fwords ffloat = function | T.Nat -> fun v1 v2 -> Bool (fnat (as_int v1) (as_int v2)) | T.Int -> fun v1 v2 -> Bool (fint (as_int v1) (as_int v2)) + | T.Int8 -> fun v1 v2 -> Bool (fint8 (as_int8 v1) (as_int8 v2)) + | T.Int16 -> fun v1 v2 -> Bool (fint16 (as_int16 v1) (as_int16 v2)) + | T.Int32 -> fun v1 v2 -> Bool (fint32 (as_int32 v1) (as_int32 v2)) + | T.Int64 -> fun v1 v2 -> Bool (fint64 (as_int64 v1) (as_int64 v2)) | T.Float -> fun v1 v2 -> Bool (ffloat (as_float v1) (as_float v2)) - | t -> word_relop fword8 fword16 fword32 fword64 t + | t -> word_relop fwords t -let ord_relop fnat fint fword8 fword16 fword32 fword64 ffloat fchar ftext = function +let ord_relop fnat fint fints fwords ffloat fchar ftext = function | T.Char -> fun v1 v2 -> Bool (fchar (as_char v1) (as_char v2)) | T.Text -> fun v1 v2 -> Bool (ftext (as_text v1) (as_text v2)) - | t -> num_relop fnat fint fword8 fword16 fword32 fword64 ffloat t + | t -> num_relop fnat fint fints fwords ffloat t -let eq_relop fnat fint fword8 fword16 fword32 fword64 ffloat fchar ftext fnull fbool = function +let eq_relop fnat fint fints fwords ffloat fchar ftext fnull fbool = function | T.Null -> fun v1 v2 -> Bool (fnull (as_null v1) (as_null v2)) | T.Bool -> fun v1 v2 -> Bool (fbool (as_bool v1) (as_bool v2)) - | t -> ord_relop fnat fint fword8 fword16 fword32 fword64 ffloat fchar ftext t + | t -> ord_relop fnat fint fints fwords ffloat fchar ftext t let relop t op = match t with | T.Prim p -> (match op with - | EqOp -> eq_relop Nat.eq Int.eq Word8.eq Word16.eq Word32.eq Word64.eq Float.eq (=) (=) (=) (=) p - | NeqOp -> eq_relop Nat.ne Int.ne Word8.ne Word16.ne Word32.ne Word64.ne Float.ne (<>) (<>) (<>) (<>) p - | LtOp -> ord_relop Nat.lt Int.lt Word8.lt_u Word16.lt_u Word32.lt_u Word64.lt_u Float.lt (<) (<) p - | GtOp -> ord_relop Nat.gt Int.gt Word8.gt_u Word16.gt_u Word32.gt_u Word64.gt_u Float.gt (>) (>) p - | LeOp -> ord_relop Nat.le Int.le Word8.le_u Word16.le_u Word32.le_u Word64.le_u Float.le (<=) (<=) p - | GeOp -> ord_relop Nat.ge Int.ge Word8.ge_u Word16.ge_u Word32.ge_u Word64.ge_u Float.ge (>=) (>=) p + | EqOp -> eq_relop Nat.eq Int.eq (Int_8.eq, Int_16.eq, Int_32.eq, Int_64.eq) (Word8.eq, Word16.eq, Word32.eq, Word64.eq) Float.eq (=) (=) (=) (=) p + | NeqOp -> eq_relop Nat.ne Int.ne (Int_8.ne, Int_16.ne, Int_32.ne, Int_64.ne) (Word8.ne, Word16.ne, Word32.ne, Word64.ne) Float.ne (<>) (<>) (<>) (<>) p + | LtOp -> ord_relop Nat.lt Int.lt (Int_8.lt, Int_16.lt, Int_32.lt, Int_64.lt) (Word8.lt_u, Word16.lt_u, Word32.lt_u, Word64.lt_u) Float.lt (<) (<) p + | GtOp -> ord_relop Nat.gt Int.gt (Int_8.gt, Int_16.gt, Int_32.gt, Int_64.gt) (Word8.gt_u, Word16.gt_u, Word32.gt_u, Word64.gt_u) Float.gt (>) (>) p + | LeOp -> ord_relop Nat.le Int.le (Int_8.le, Int_16.le, Int_32.le, Int_64.le) (Word8.le_u, Word16.le_u, Word32.le_u, Word64.le_u) Float.le (<=) (<=) p + | GeOp -> ord_relop Nat.ge Int.ge (Int_8.ge, Int_16.ge, Int_32.ge, Int_64.ge) (Word8.ge_u, Word16.ge_u, Word32.ge_u, Word64.ge_u) Float.ge (>=) (>=) p ) | T.Non -> impossible | _ -> raise (Invalid_argument "relop") diff --git a/src/as_values/prim.ml b/src/as_values/prim.ml index 20575609b20..3e6505ec9cc 100644 --- a/src/as_values/prim.ml +++ b/src/as_values/prim.ml @@ -7,11 +7,10 @@ module Conv = struct open Big_int let of_signed_Word32 w = to_int (logand 0xFFFFFFFFn (of_int32 w)) - let two = big_int_of_int 2 - let twoRaised62 = power_big_int_positive_int two 62 - let twoRaised63 = power_big_int_positive_int two 63 + let twoRaised62 = power_int_positive_int 2 62 + let twoRaised63 = power_int_positive_int 2 63 let word_twoRaised63 = Word64.(pow 2L 63L) - let twoRaised64 = power_big_int_positive_int two 64 + let twoRaised64 = power_int_positive_int 2 64 let word64_of_nat_big_int i = assert (sign_big_int i > -1); @@ -35,55 +34,158 @@ module Conv = struct match int_of_big_int_opt i with | Some n -> n | _ -> int_of_big_int (mod_big_int i twoRaised62) + + (* for q in {0, -1} return i + q * offs *) + let to_signed i q offs = if Big_int.sign_big_int q = 0 then i else i - offs + let to_signed_big_int i q offs = Big_int.(if sign_big_int q = 0 then i else sub_big_int i offs) end (* Conv *) +let range_violation () = raise (Invalid_argument "numeric overflow") let prim = function | "abs" -> fun v k -> k (Int (Nat.abs (as_int v))) + | "Nat8->Word8" -> fun v k -> + let i = Nat8.to_int (as_nat8 v) + in k (Word8 (Word8.of_int_u i)) | "Nat->Word8" -> fun v k -> let i = Conv.wrapped_int_of_big_int (as_int v) in k (Word8 (Word8.of_int_u i)) + | "Nat->Nat8" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) (Big_int.power_int_positive_int 2 8) in + let i = Big_int.int_of_big_int r + in Big_int.(if eq_big_int q zero_big_int then k (Nat8 (Nat8.of_int i)) else range_violation ()) + | "Int8->Word8" -> fun v k -> + let i = Int_8.to_int (as_int8 v) + in k (Word8 (Word8.of_int_s i)) | "Int->Word8" -> fun v k -> let i = Conv.wrapped_int_of_big_int (as_int v) in k (Word8 (Word8.of_int_s i)) + | "Int->Int8" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) (Big_int.power_int_positive_int 2 7) in + let i = Big_int.int_of_big_int r in + Big_int. + (if eq_big_int q zero_big_int || eq_big_int q (pred_big_int zero_big_int) + then k (Int8(Int_8.of_int (Conv.to_signed i q 0x80))) else range_violation ()) + | "Nat16->Word16" -> fun v k -> + let i = Nat16.to_int (as_nat16 v) + in k (Word16 (Word16.of_int_u i)) | "Nat->Word16" -> fun v k -> let i = Conv.wrapped_int_of_big_int (as_int v) in k (Word16 (Word16.of_int_u i)) + | "Nat->Nat16" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) (Big_int.power_int_positive_int 2 16) in + let i = Big_int.int_of_big_int r + in Big_int.(if eq_big_int q zero_big_int then k (Nat16 (Nat16.of_int i)) else range_violation ()) + | "Int16->Word16" -> fun v k -> + let i = Int_16.to_int (as_int16 v) + in k (Word16 (Word16.of_int_s i)) | "Int->Word16" -> fun v k -> let i = Conv.wrapped_int_of_big_int (as_int v) in k (Word16 (Word16.of_int_s i)) + | "Int->Int16" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) (Big_int.power_int_positive_int 2 15) in + let i = Big_int.int_of_big_int r in + Big_int. + (if eq_big_int q zero_big_int || eq_big_int q (pred_big_int zero_big_int) + then k (Int16(Int_16.of_int (Conv.to_signed i q 0x8000))) else range_violation ()) + | "Nat32->Word32" -> fun v k -> + let i = Nat32.to_int (as_nat32 v) + in k (Word32 (Word32.of_int_u i)) | "Nat->Word32" -> fun v k -> let i = Conv.wrapped_int_of_big_int (as_int v) in k (Word32 (Word32.of_int_u i)) + | "Nat->Nat32" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) (Big_int.power_int_positive_int 2 32) in + let i = Big_int.int_of_big_int r + in Big_int.(if eq_big_int q zero_big_int then k (Nat32 (Nat32.of_int i)) else range_violation ()) + | "Int32->Word32" -> fun v k -> + let i = Int_32.to_int (as_int32 v) + in k (Word32 (Word32.of_int_s i)) | "Int->Word32" -> fun v k -> let i = Conv.wrapped_int_of_big_int (as_int v) in k (Word32 (Word32.of_int_s i)) + | "Int->Int32" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) (Big_int.power_int_positive_int 2 31) in + let i = Big_int.int_of_big_int r in + Big_int. + (if eq_big_int q zero_big_int || eq_big_int q (pred_big_int zero_big_int) + then k (Int32 (Int_32.of_int (Conv.to_signed i q 0x80000000))) else range_violation ()) + | "Nat64->Word64" -> fun v k -> + let q, r = Big_int.quomod_big_int (Nat64.to_big_int (as_nat64 v)) Conv.twoRaised63 in + let i = Conv.(to_signed_big_int r q twoRaised63) in + k (Word64 (Big_int.int64_of_big_int i)) | "Nat->Word64" -> fun v k -> k (Word64 (Conv.word64_of_nat_big_int (as_int v))) + | "Nat->Nat64" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) Conv.twoRaised64 in + Big_int. + (if eq_big_int q zero_big_int + then k (Nat64 (Nat64.of_big_int r)) + else range_violation ()) + | "Int64->Word64" -> fun v k -> k (Word64 (Big_int.int64_of_big_int (Int_64.to_big_int (as_int64 v)))) | "Int->Word64" -> fun v k -> k (Word64 (Conv.word64_of_big_int (as_int v))) + | "Int->Int64" -> fun v k -> + let q, r = Big_int.quomod_big_int (as_int v) Conv.twoRaised63 in + Big_int. + (if eq_big_int q zero_big_int || eq_big_int q (pred_big_int zero_big_int) + then k (Int64 (Int_64.of_big_int Conv.(to_signed_big_int r q twoRaised63))) + else range_violation ()) | "Word8->Nat" -> fun v k -> let i = Int32.to_int (Int32.shift_right_logical (Word8.to_bits (as_word8 v)) 24) in k (Int (Big_int.big_int_of_int i)) + | "Word8->Nat8" -> fun v k -> + let i = Int32.to_int (Int32.shift_right_logical (Word8.to_bits (as_word8 v)) 24) + in k (Nat8 (Nat8.of_int i)) + | "Int8->Int" -> fun v k -> k (Int (Int.of_int (Int_8.to_int (as_int8 v)))) + | "Nat8->Nat" -> fun v k -> k (Int (Nat.of_int (Nat8.to_int (as_nat8 v)))) | "Word8->Int" -> fun v k -> let i = Int32.to_int (Int32.shift_right (Word8.to_bits (as_word8 v)) 24) in k (Int (Big_int.big_int_of_int i)) + | "Word8->Int8" -> fun v k -> + let i = Int32.to_int (Int32.shift_right (Word8.to_bits (as_word8 v)) 24) + in k (Int8 (Int_8.of_int i)) | "Word16->Nat" -> fun v k -> let i = Int32.to_int (Int32.shift_right_logical (Word16.to_bits (as_word16 v)) 16) in k (Int (Big_int.big_int_of_int i)) + | "Word16->Nat16" -> fun v k -> + let i = Int32.to_int (Int32.shift_right_logical (Word16.to_bits (as_word16 v)) 16) + in k (Nat16 (Nat16.of_int i)) + | "Int16->Int" -> fun v k -> k (Int (Int.of_int (Int_16.to_int (as_int16 v)))) + | "Nat16->Nat" -> fun v k -> k (Int (Nat.of_int (Nat16.to_int (as_nat16 v)))) | "Word16->Int" -> fun v k -> let i = Int32.to_int (Int32.shift_right (Word16.to_bits (as_word16 v)) 16) in k (Int (Big_int.big_int_of_int i)) + | "Word16->Int16" -> fun v k -> + let i = Int32.to_int (Int32.shift_right (Word16.to_bits (as_word16 v)) 16) + in k (Int16 (Int_16.of_int i)) + | "Int32->Int" -> fun v k -> k (Int (Int.of_int (Int_32.to_int (as_int32 v)))) + | "Nat32->Nat" -> fun v k -> k (Int (Nat.of_int (Nat32.to_int (as_nat32 v)))) | "Word32->Nat" -> fun v k -> let i = Conv.of_signed_Word32 (as_word32 v) in k (Int (Big_int.big_int_of_int i)) | "Word32->Int" -> fun v k -> k (Int (Big_int.big_int_of_int32 (as_word32 v))) + | "Word32->Int32" -> fun v k -> + let i = Big_int.(int_of_big_int (big_int_of_int32 (as_word32 v))) in + k (Int32 (Int_32.of_int i)) + | "Word32->Nat32" -> fun v k -> + let i = Big_int.(int_of_big_int (big_int_of_int32 (as_word32 v))) in + let i' = if i < 0 then i + 0x100000000 else i in + k (Nat32 (Nat32.of_int i')) + | "Int64->Int" -> fun v k -> k (Int (Int_64.to_big_int (as_int64 v))) + | "Nat64->Nat" -> fun v k -> k (Int (Nat64.to_big_int (as_nat64 v))) | "Word64->Nat" -> fun v k -> let i = Conv.big_int_of_unsigned_word64 (as_word64 v) in k (Int i) + | "Word64->Nat64" -> fun v k -> + let i = Conv.big_int_of_unsigned_word64 (as_word64 v) + in k (Nat64 (Nat64.of_big_int i)) | "Word64->Int" -> fun v k -> k (Int (Big_int.big_int_of_int64 (as_word64 v))) + | "Word64->Int64" -> fun v k -> + let i = Big_int.big_int_of_int64 (as_word64 v) + in k (Int64 (Int_64.of_big_int i)) | "Char->Word32" -> fun v k -> let i = as_char v diff --git a/src/as_values/show.ml b/src/as_values/show.ml index d89c67ffb15..22335a92613 100644 --- a/src/as_values/show.ml +++ b/src/as_values/show.ml @@ -3,20 +3,20 @@ module T = As_types.Type (* Entry point for type checking: *) let rec can_show t = - let t = T.normalize t in - match t with - | T.Prim T.Bool - | T.Prim T.Nat - | T.Prim T.Int - | T.Prim T.Text - | T.Prim T.Null -> true - | T.Tup ts' -> List.for_all can_show ts' - | T.Opt t' -> can_show t' - | T.Array t' -> can_show (T.as_immut t') - | T.Obj (T.Object _, fs) -> - List.for_all (fun f -> can_show (T.as_immut f.T.typ)) fs - | T.Variant cts -> - List.for_all (fun f -> can_show f.T.typ) cts + let open T in + match normalize t with + | Prim (Bool|Nat|Int|Text|Null) -> true + | Prim (Nat8|Int8|Word8) + | Prim (Nat16|Int16|Word16) + | Prim (Nat32|Int32|Word32) + | Prim (Nat64|Int64|Word64) -> true + | Tup ts' -> List.for_all can_show ts' + | Opt t' -> can_show t' + | Array t' -> can_show (as_immut t') + | Obj (Object _, fs) -> + List.for_all (fun f -> can_show (as_immut f.typ)) fs + | Variant cts -> + List.for_all (fun f -> can_show f.typ) cts | _ -> false (* Entry point for the interpreter (reference implementation) *) @@ -25,8 +25,19 @@ let rec show_val t v = let t = T.normalize t in match t, v with | T.Prim T.Bool, Value.Bool b -> if b then "true" else "false" - | T.Prim T.Nat, Value.Int i -> Value.Int.to_string i - | T.Prim T.Int, Value.Int i -> Value.Int.to_string i + | T.(Prim (Nat|Int)), Value.Int i -> Value.Int.to_string i + | T.(Prim Nat8), Value.Nat8 i -> Value.Nat8.to_string i + | T.(Prim Nat16), Value.Nat16 i -> Value.Nat16.to_string i + | T.(Prim Nat32), Value.Nat32 i -> Value.Nat32.to_string i + | T.(Prim Nat64), Value.Nat64 i -> Value.Nat64.to_string i + | T.(Prim Int8), Value.Int8 i -> Value.Int_8.to_string i + | T.(Prim Int16), Value.Int16 i -> Value.Int_16.to_string i + | T.(Prim Int32), Value.Int32 i -> Value.Int_32.to_string i + | T.(Prim Int64), Value.Int64 i -> Value.Int_64.to_string i + | T.(Prim Word8), Value.Word8 i -> Value.Word8.to_string i + | T.(Prim Word16), Value.Word16 i -> Value.Word16.to_string i + | T.(Prim Word32), Value.Word32 i -> Value.Word32.to_string i + | T.(Prim Word64), Value.Word64 i -> Value.Word64.to_string i | T.Prim T.Text, Value.Text s -> "\"" ^ s ^ "\"" | T.Prim T.Null, Value.Null -> "null" | T.Opt _, Value.Null -> "null" diff --git a/src/as_values/value.ml b/src/as_values/value.ml index 53e284db16b..73a3144cba1 100644 --- a/src/as_values/value.ml +++ b/src/as_values/value.ml @@ -142,6 +142,8 @@ sig val compare : t -> t -> int val to_int : t -> int val of_int : int -> t + val to_big_int : t -> Big_int.big_int + val of_big_int : Big_int.big_int -> t val of_string : string -> t val to_string : t -> string val to_pretty_string : t -> string @@ -172,6 +174,8 @@ struct let compare = compare_big_int let to_int = int_of_big_int let of_int = big_int_of_int + let of_big_int i = i + let to_big_int i = i let to_string i = string_of_big_int i let to_pretty_string i = group_num (string_of_big_int i) let of_string s = @@ -193,6 +197,45 @@ struct if ge z zero then z else raise (Invalid_argument "Nat.sub") end +module RangeLimited(Rep : NumType)(Range : sig val is_range : Rep.t -> bool end) : NumType = +struct + let check i = + if Range.is_range i then i + else raise (Invalid_argument "value out of bounds") + + include Rep + let neg a = let res = Rep.neg a in check res + let abs a = let res = Rep.abs a in check res + let add a b = let res = Rep.add a b in check res + let mul a b = let res = Rep.mul a b in check res + let div a b = let res = Rep.div a b in check res + let pow a b = let res = Rep.pow a b in check res + let of_int i = let res = Rep.of_int i in check res + let of_big_int i = let res = Rep.of_big_int i in check res + let of_string s = let res = Rep.of_string s in check res +end + +module NatRange(Limit : sig val upper : Big_int.big_int end) = +struct + open Big_int + let is_range n = ge_big_int n zero_big_int && lt_big_int n Limit.upper +end + +module Nat8 = RangeLimited(Nat)(NatRange(struct let upper = Big_int.big_int_of_int 0x100 end)) +module Nat16 = RangeLimited(Nat)(NatRange(struct let upper = Big_int.big_int_of_int 0x10000 end)) +module Nat32 = RangeLimited(Nat)(NatRange(struct let upper = Big_int.big_int_of_int 0x100000000 end)) +module Nat64 = RangeLimited(Nat)(NatRange(struct let upper = Big_int.power_int_positive_int 2 64 end)) + +module IntRange(Limit : sig val upper : Big_int.big_int end) = +struct + open Big_int + let is_range n = ge_big_int n (minus_big_int Limit.upper) && lt_big_int n Limit.upper +end + +module Int_8 = RangeLimited(Int)(IntRange(struct let upper = Big_int.big_int_of_int 0x80 end)) +module Int_16 = RangeLimited(Int)(IntRange(struct let upper = Big_int.big_int_of_int 0x8000 end)) +module Int_32 = RangeLimited(Int)(IntRange(struct let upper = Big_int.big_int_of_int 0x80000000 end)) +module Int_64 = RangeLimited(Int)(IntRange(struct let upper = Big_int.power_int_positive_int 2 63 end)) (* Types *) @@ -204,6 +247,14 @@ and value = | Null | Bool of bool | Int of Int.t + | Int8 of Int_8.t + | Int16 of Int_16.t + | Int32 of Int_32.t + | Int64 of Int_64.t + | Nat8 of Nat8.t + | Nat16 of Nat16.t + | Nat32 of Nat32.t + | Nat64 of Nat64.t | Word8 of Word8.t | Word16 of Word16.t | Word32 of Word32.t @@ -240,6 +291,14 @@ let invalid s = raise (Invalid_argument ("Value." ^ s)) let as_null = function Null -> () | _ -> invalid "as_null" let as_bool = function Bool b -> b | _ -> invalid "as_bool" let as_int = function Int n -> n | _ -> invalid "as_int" +let as_int8 = function Int8 w -> w | _ -> invalid "as_int8" +let as_int16 = function Int16 w -> w | _ -> invalid "as_int16" +let as_int32 = function Int32 w -> w | _ -> invalid "as_int32" +let as_int64 = function Int64 w -> w | _ -> invalid "as_int64" +let as_nat8 = function Nat8 w -> w | _ -> invalid "as_nat8" +let as_nat16 = function Nat16 w -> w | _ -> invalid "as_nat16" +let as_nat32 = function Nat32 w -> w | _ -> invalid "as_nat32" +let as_nat64 = function Nat64 w -> w | _ -> invalid "as_nat64" let as_word8 = function Word8 w -> w | _ -> invalid "as_word8" let as_word16 = function Word16 w -> w | _ -> invalid "as_word16" let as_word32 = function Word32 w -> w | _ -> invalid "as_word32" @@ -325,6 +384,14 @@ let rec compare x1 x2 = if x1 == x2 then 0 else match x1, x2 with | Int n1, Int n2 -> Int.compare n1 n2 + | Int8 n1, Int8 n2 -> Int_8.compare n1 n2 + | Int16 n1, Int16 n2 -> Int_16.compare n1 n2 + | Int32 n1, Int32 n2 -> Int_32.compare n1 n2 + | Int64 n1, Int64 n2 -> Int_64.compare n1 n2 + | Nat8 n1, Nat8 n2 -> Nat8.compare n1 n2 + | Nat16 n1, Nat16 n2 -> Nat16.compare n1 n2 + | Nat32 n1, Nat32 n2 -> Nat32.compare n1 n2 + | Nat64 n1, Nat64 n2 -> Nat64.compare n1 n2 | Opt v1, Opt v2 -> compare v1 v2 | Tup vs1, Tup vs2 -> Lib.List.compare compare vs1 vs2 | Array a1, Array a2 -> Lib.Array.compare compare a1 a2 @@ -363,6 +430,14 @@ let rec string_of_val_nullary d = function | Null -> "null" | Bool b -> if b then "true" else "false" | Int i -> Int.to_pretty_string i + | Int8 w -> Int_8.to_pretty_string w + | Int16 w -> Int_16.to_pretty_string w + | Int32 w -> Int_32.to_pretty_string w + | Int64 w -> Int_64.to_pretty_string w + | Nat8 w -> Nat8.to_pretty_string w + | Nat16 w -> Nat16.to_pretty_string w + | Nat32 w -> Nat32.to_pretty_string w + | Nat64 w -> Nat64.to_pretty_string w | Word8 w -> Word8.to_pretty_string w | Word16 w -> Word16.to_pretty_string w | Word32 w -> Word32.to_pretty_string w diff --git a/src/as_values/value.mli b/src/as_values/value.mli index b9fa22c7162..8ca39331c91 100644 --- a/src/as_values/value.mli +++ b/src/as_values/value.mli @@ -33,6 +33,8 @@ sig val compare : t -> t -> int val to_int : t -> int val of_int : int -> t + val to_big_int : t -> Big_int.big_int + val of_big_int : Big_int.big_int -> t val of_string : string -> t val to_string : t -> string val to_pretty_string : t -> string @@ -53,6 +55,14 @@ module Float : FloatType with type bits = int64 and type t = Wasm.F64.t module Nat : NumType with type t = Big_int.big_int module Int : NumType with type t = Big_int.big_int +module Int_8 : NumType +module Int_16 : NumType +module Int_32 : NumType +module Int_64 : NumType +module Nat8 : NumType +module Nat16 : NumType +module Nat32 : NumType +module Nat64 : NumType (* Environment *) @@ -69,6 +79,14 @@ and value = | Null | Bool of bool | Int of Int.t + | Int8 of Int_8.t + | Int16 of Int_16.t + | Int32 of Int_32.t + | Int64 of Int_64.t + | Nat8 of Nat8.t + | Nat16 of Nat16.t + | Nat32 of Nat32.t + | Nat64 of Nat64.t | Word8 of Word8.t | Word16 of Word16.t | Word32 of Word32.t @@ -107,6 +125,14 @@ val async_func : int -> func -> value val as_null : value -> unit val as_bool : value -> bool val as_int : value -> Int.t +val as_int8 : value -> Int_8.t +val as_int16 : value -> Int_16.t +val as_int32 : value -> Int_32.t +val as_int64 : value -> Int_64.t +val as_nat8 : value -> Nat8.t +val as_nat16 : value -> Nat16.t +val as_nat32 : value -> Nat32.t +val as_nat64 : value -> Nat64.t val as_word8 : value -> Word8.t val as_word16 : value -> Word16.t val as_word32 : value -> Word32.t diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index b5a18c0b506..5f8c8c26e01 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -1148,23 +1148,18 @@ module Closure = struct end (* Closure *) -module BoxedWord = struct - (* We store large nats and ints in immutable boxed 64bit heap objects. +module BoxedWord64 = struct + (* We store large word64s, nat64s and int64s in immutable boxed 64bit heap objects. Small values (just <2^5 for now, so that both code paths are well-tested) are stored unboxed, tagged, see BitTagged. - The heap layout of a BoxedWord is: + The heap layout of a BoxedWord64 is: ┌─────┬─────┬─────┐ │ tag │ i64 │ └─────┴─────┴─────┘ - Note, that due to the equivalence of in-memory and on-stack - representations, the 64-bit word type is also represented in this - way. As we get proper bigints, the memory representations should - be disambiguated and stack representations adapted. (Renaming - those will point out where the backend needs adjustments.) *) let payload_field = Tagged.header_size @@ -1200,7 +1195,7 @@ module BoxedWord = struct (* from/to SR.UnboxedWord64 *) let to_word64 env = G.nop let from_word64 env = G.nop (* TODO trap if negative *) - let from_signed_word64 env = G.nop + let _from_signed_word64 env = G.nop let to_word32 env = G.i (Convert (Wasm.Values.I32 I32Op.WrapI64)) let from_word32 env = G.i (Convert (Wasm.Values.I64 I64Op.ExtendUI32)) let from_signed_word32 env = G.i (Convert (Wasm.Values.I64 I64Op.ExtendSI32)) @@ -1233,7 +1228,7 @@ module BoxedWord = struct G.i (Binary (Wasm.Values.I64 I64Op.Mul))))) in pow () -end (* BoxedWord *) +end (* BoxedWord64 *) module BoxedSmallWord = struct @@ -1284,10 +1279,12 @@ module UnboxedSmallWord = struct there are certain differences that are type based. This module provides helpers to abstract over those. *) - let shift_of_type = function - | Type.Word8 -> 24l - | Type.Word16 -> 16l - | _ -> 0l + let bits_of_type = function + | Type.(Int8|Nat8|Word8) -> 8 + | Type.(Int16|Nat16|Word16) -> 16 + | _ -> 32 + + let shift_of_type ty = Int32.of_int (32 - bits_of_type ty) let bitwidth_mask_of_type = function | Type.Word8 -> 0b111l @@ -1315,12 +1312,13 @@ module UnboxedSmallWord = struct (* Makes sure that the word payload (e.g. shift/rotate amount) is in the LSB bits of the word. *) let lsb_adjust = function - | Type.Word32 -> G.nop - | ty -> compile_shrU_const (shift_of_type ty) + | Type.(Int32|Nat32|Word32) -> G.nop + | Type.(Int8|Nat8|Word8|Int16|Nat16|Word16) as ty -> compile_shrU_const (shift_of_type ty) + | _ -> assert false (* Makes sure that the word payload (e.g. operation result) is in the MSB bits of the word. *) let msb_adjust = function - | Type.Word32 -> G.nop + | Type.(Int32|Nat32|Word32) -> G.nop | ty -> shift_leftWordNtoI32 (shift_of_type ty) (* Makes sure that the word representation invariant is restored. *) @@ -1406,6 +1404,9 @@ module UnboxedSmallWord = struct set_res ^^ compile_unboxed_const 4l))) + let lit env ty v = + compile_unboxed_const Int32.(shift_left (of_int v) (to_int (shift_of_type ty))) + end (* UnboxedSmallWord *) type comparator = Lt | Le | Ge | Gt @@ -1418,15 +1419,15 @@ sig (* word from SR.Vanilla, lossy, raw bits *) val truncate_to_word32 : E.t -> G.t - val _truncate_to_word64 : E.t -> G.t + val truncate_to_word64 : E.t -> G.t (* unsigned word to SR.Vanilla *) val from_word32 : E.t -> G.t val from_word64 : E.t -> G.t (* signed word to SR.Vanilla *) - val from_signed_word64 : E.t -> G.t val from_signed_word32 : E.t -> G.t + val from_signed_word64 : E.t -> G.t (* buffers *) (* given a numeric object on stack (vanilla), @@ -1476,24 +1477,24 @@ sig (* given a numeric object on the stack as skewed pointer, check whether it can be faithfully stored in N bits, including a leading sign bit leaves boolean result on the stack - N must be 2..63 + N must be 2..64 *) - val _fits_signed_bits : E.t -> int -> G.t + val fits_signed_bits : E.t -> int -> G.t (* given a numeric object on the stack as skewed pointer, check whether it can be faithfully stored in N unsigned bits leaves boolean result on the stack N must be 1..64 *) - val _fits_unsigned_bits : E.t -> int -> G.t + val fits_unsigned_bits : E.t -> int -> G.t end [@@@warning "-60"] (* Do not warn about unused module *) module BigNum64 : BigNumType = struct - include BoxedWord + include BoxedWord64 (* examine the skewed pointer and determine if the unsigned number it points to fits into N bits *) - let _fits_unsigned_bits env = function + let fits_unsigned_bits env = function | 64 -> G.i Drop ^^ compile_unboxed_one | n when n > 64 || n < 1 -> assert false | n -> @@ -1504,8 +1505,9 @@ module BigNum64 : BigNumType = struct (* examine the skewed pointer and determine if the signed number it points to fits into N bits *) - let _fits_signed_bits env = function - | n when n > 63 || n < 2 -> assert false + let fits_signed_bits env = function + | n when n > 64 || n < 2 -> assert false + | 64 -> Bool.lit true | n -> let set_num, get_num = new_local64 env "num" in unbox env ^^ set_num ^^ get_num ^^ get_num ^^ @@ -1519,19 +1521,20 @@ module BigNum64 : BigNumType = struct let to_word32 env = let (set_num, get_num) = new_local env "num" in set_num ^^ get_num ^^ - _fits_unsigned_bits env 32 ^^ - E.else_trap_with env "Losing precision" ^^ + fits_unsigned_bits env 32 ^^ + E.else_trap_with env "losing precision" ^^ get_num ^^ unbox env ^^ - BoxedWord.to_word32 env + BoxedWord64.to_word32 env - let from_word32 env = BoxedWord.from_word32 env ^^ box env - let from_signed_word32 env = BoxedWord.from_signed_word32 env ^^ box env - let to_word64 env = unbox env ^^ BoxedWord.to_word64 env - let from_word64 env = BoxedWord.from_word64 env ^^ box env + let from_word32 env = BoxedWord64.from_word32 env ^^ box env + let from_signed_word32 env = BoxedWord64.from_signed_word32 env ^^ box env + let from_signed_word64 env = G.i Unreachable (* FIXME *) + let to_word64 env = unbox env ^^ BoxedWord64.to_word64 env + let from_word64 env = BoxedWord64.from_word64 env ^^ box env - let truncate_to_word32 env = unbox env ^^ BoxedWord.to_word32 env - let _truncate_to_word64 env = unbox env ^^ BoxedWord.to_word64 env + let truncate_to_word32 env = unbox env ^^ BoxedWord64.to_word32 env + let truncate_to_word64 env = unbox env ^^ BoxedWord64.to_word64 env let compile_lit env n = compile_const_64 (Big_int.int64_of_big_int n) ^^ box env @@ -1577,11 +1580,11 @@ module BigNum64 : BigNumType = struct let compile_signed_mod = with_both_unboxed (G.i (Binary (Wasm.Values.I64 I64Op.RemS))) let compile_unsigned_div = with_both_unboxed (G.i (Binary (Wasm.Values.I64 I64Op.DivU))) let compile_unsigned_rem = with_both_unboxed (G.i (Binary (Wasm.Values.I64 I64Op.RemU))) - let compile_unsigned_sub env = with_both_unboxed (BoxedWord.compile_unsigned_sub env) env - let compile_unsigned_pow env = with_both_unboxed (BoxedWord.compile_unsigned_pow env) env + let compile_unsigned_sub env = with_both_unboxed (BoxedWord64.compile_unsigned_sub env) env + let compile_unsigned_pow env = with_both_unboxed (BoxedWord64.compile_unsigned_pow env) env let compile_neg env = - Func.share_code1 env "negInt" ("n", I32Type) [I32Type] (fun env get_n -> + Func.share_code1 env "neg" ("n", I32Type) [I32Type] (fun env get_n -> compile_lit env (Big_int.big_int_of_int 0) ^^ get_n ^^ compile_signed_sub env @@ -1609,7 +1612,7 @@ module BigNumLibtommmath : BigNumType = struct let to_word64 env = E.call_import env "rts" "bigint_to_word64_trap" let truncate_to_word32 env = E.call_import env "rts" "bigint_to_word32_wrap" - let _truncate_to_word64 env = E.call_import env "rts" "bigint_to_word64_wrap" + let truncate_to_word64 env = E.call_import env "rts" "bigint_to_word64_wrap" let from_word32 env = E.call_import env "rts" "bigint_of_word32" let from_word64 env = E.call_import env "rts" "bigint_of_word64" @@ -1700,11 +1703,11 @@ module BigNumLibtommmath : BigNumType = struct | Gt -> "rts_bigint_gt" in G.i (Call (nr (E.built_in env fn))) - let _fits_signed_bits env bits = + let fits_signed_bits env bits = G.i (Call (nr (E.built_in env ("rts_bigint_2complement_bits")))) ^^ - compile_unboxed_const (Int32.of_int (bits - 1)) ^^ + compile_unboxed_const (Int32.of_int bits) ^^ G.i (Compare (Wasm.Values.I32 I32Op.LeU)) - let _fits_unsigned_bits env bits = + let fits_unsigned_bits env bits = G.i (Call (nr (E.built_in env ("rts_bigint_count_bits")))) ^^ compile_unboxed_const (Int32.of_int bits) ^^ G.i (Compare (Wasm.Values.I32 I32Op.LeU)) @@ -2865,10 +2868,10 @@ module Serialization = struct begin match t with | Prim Nat -> inc_data_size (get_x ^^ BigNum.compile_data_size_unsigned env) | Prim Int -> inc_data_size (get_x ^^ BigNum.compile_data_size_signed env) - | Prim Word64 -> inc_data_size (compile_unboxed_const 8l) (* 64 bit *) - | Prim Word8 -> inc_data_size (compile_unboxed_const 1l) - | Prim Word16 -> inc_data_size (compile_unboxed_const 2l) - | Prim Word32 -> inc_data_size (compile_unboxed_const 4l) + | Prim (Int8|Nat8|Word8) -> inc_data_size (compile_unboxed_const 1l) + | Prim (Int16|Nat16|Word16) -> inc_data_size (compile_unboxed_const 2l) + | Prim (Int32|Nat32|Word32) -> inc_data_size (compile_unboxed_const 4l) + | Prim (Int64|Nat64|Word64) -> inc_data_size (compile_unboxed_const 8l) | Prim Bool -> inc_data_size (compile_unboxed_const 1l) | Tup ts -> G.concat_mapi (fun i t -> @@ -2968,22 +2971,22 @@ module Serialization = struct get_x ^^ BigNum.compile_store_to_data_buf_signed env ^^ advance_data_buf - | Prim Word64 -> + | Prim (Int64|Nat64|Word64) -> get_data_buf ^^ - get_x ^^ BoxedWord.unbox env ^^ + get_x ^^ BoxedWord64.unbox env ^^ G.i (Store {ty = I64Type; align = 0; offset = 0l; sz = None}) ^^ compile_unboxed_const 8l ^^ advance_data_buf - | Prim Word32 -> + | Prim (Int32|Nat32|Word32) -> get_data_buf ^^ get_x ^^ BoxedSmallWord.unbox env ^^ G.i (Store {ty = I32Type; align = 0; offset = 0l; sz = None}) ^^ compile_unboxed_const 4l ^^ advance_data_buf - | Prim Word16 -> + | Prim (Int16|Nat16|Word16) -> get_data_buf ^^ get_x ^^ UnboxedSmallWord.lsb_adjust Word16 ^^ G.i (Store {ty = I32Type; align = 0; offset = 0l; sz = Some Wasm.Memory.Pack16}) ^^ compile_unboxed_const 2l ^^ advance_data_buf - | Prim Word8 -> + | Prim (Int8|Nat8|Word8) -> get_data_buf ^^ get_x ^^ UnboxedSmallWord.lsb_adjust Word8 ^^ G.i (Store {ty = I32Type; align = 0; offset = 0l; sz = Some Wasm.Memory.Pack8}) ^^ @@ -3098,22 +3101,22 @@ module Serialization = struct get_data_buf ^^ BigNum.compile_load_from_data_buf_signed env ^^ advance_data_buf - | Prim Word64 -> + | Prim (Int64|Nat64|Word64) -> get_data_buf ^^ G.i (Load {ty = I64Type; align = 2; offset = 0l; sz = None}) ^^ - BoxedWord.box env ^^ + BoxedWord64.box env ^^ compile_unboxed_const 8l ^^ advance_data_buf (* 64 bit *) - | Prim Word32 -> + | Prim (Int32|Nat32|Word32) -> get_data_buf ^^ G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = None}) ^^ BoxedSmallWord.box env ^^ compile_unboxed_const 4l ^^ advance_data_buf - | Prim Word16 -> + | Prim (Int16|Nat16|Word16) -> get_data_buf ^^ G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = Some (Wasm.Memory.Pack16, Wasm.Memory.ZX)}) ^^ UnboxedSmallWord.msb_adjust Word16 ^^ compile_unboxed_const 2l ^^ advance_data_buf - | Prim Word8 -> + | Prim (Int8|Nat8|Word8) -> get_data_buf ^^ G.i (Load {ty = I32Type; align = 0; offset = 0l; sz = Some (Wasm.Memory.Pack8, Wasm.Memory.ZX)}) ^^ UnboxedSmallWord.msb_adjust Word8 ^^ @@ -3594,14 +3597,15 @@ module StackRep = struct if n = 1 then UnboxedReference else UnboxedRefTuple n (* The stack rel of a primitive type, i.e. what the binary operators expect *) - let of_type : Type.typ -> t = function - | Type.Prim Type.Bool -> bool - | Type.Prim Type.Nat - | Type.Prim Type.Int -> Vanilla - | Type.Prim Type.Word64 -> UnboxedWord64 - | Type.Prim Type.Word32 -> UnboxedWord32 - | Type.Prim Type.(Word8 | Word16 | Char) -> Vanilla - | Type.Prim Type.Text -> Vanilla + let of_type t = + let open Type in + match normalize t with + | Prim Bool -> SR.bool + | Prim (Nat | Int) -> Vanilla + | Prim (Nat64 | Int64 | Word64) -> UnboxedWord64 + | Prim (Nat32 | Int32 | Word32) -> UnboxedWord32 + | Prim (Nat8 | Nat16 | Int8 | Int16 | Word8 | Word16 | Char) -> Vanilla + | Prim Text -> Vanilla | p -> todo "of_type" (Arrange_ir.typ p) Vanilla let to_block_type env = function @@ -3716,8 +3720,8 @@ module StackRep = struct adjust env sr (UnboxedTuple n) ^^ unbox_reference_n env n - | UnboxedWord64, Vanilla -> BoxedWord.box env - | Vanilla, UnboxedWord64 -> BoxedWord.unbox env + | UnboxedWord64, Vanilla -> BoxedWord64.box env + | Vanilla, UnboxedWord64 -> BoxedWord64.unbox env | UnboxedWord32, Vanilla -> BoxedSmallWord.box env | Vanilla, UnboxedWord32 -> BoxedSmallWord.unbox env @@ -4360,18 +4364,31 @@ end (* AllocHow *) (* The actual compiler code that looks at the AST *) +let nat64_to_int64 n = + let open Big_int in + let twoRaised63 = power_int_positive_int 2 63 in + let q, r = quomod_big_int (Value.Nat64.to_big_int n) twoRaised63 in + if sign_big_int q = 0 then r else sub_big_int r twoRaised63 + let compile_lit env lit = try match lit with (* Booleans are directly in Vanilla representation *) | BoolLit false -> SR.bool, Bool.lit false | BoolLit true -> SR.bool, Bool.lit true - (* This maps int to int32, instead of a proper arbitrary precision library *) | IntLit n | NatLit n -> SR.Vanilla, BigNum.compile_lit env n | Word8Lit n -> SR.Vanilla, compile_unboxed_const (Value.Word8.to_bits n) | Word16Lit n -> SR.Vanilla, compile_unboxed_const (Value.Word16.to_bits n) | Word32Lit n -> SR.UnboxedWord32, compile_unboxed_const n | Word64Lit n -> SR.UnboxedWord64, compile_const_64 n + | Int8Lit n -> SR.Vanilla, UnboxedSmallWord.lit env Type.Int8 (Value.Int_8.to_int n) + | Nat8Lit n -> SR.Vanilla, UnboxedSmallWord.lit env Type.Nat8 (Value.Nat8.to_int n) + | Int16Lit n -> SR.Vanilla, UnboxedSmallWord.lit env Type.Int16 (Value.Int_16.to_int n) + | Nat16Lit n -> SR.Vanilla, UnboxedSmallWord.lit env Type.Nat16 (Value.Nat16.to_int n) + | Int32Lit n -> SR.UnboxedWord32, compile_unboxed_const (Int32.of_int (Value.Int_32.to_int n)) + | Nat32Lit n -> SR.UnboxedWord32, compile_unboxed_const (Int32.of_int (Value.Nat32.to_int n)) + | Int64Lit n -> SR.UnboxedWord64, compile_const_64 (Big_int.int64_of_big_int (Value.Int_64.to_big_int n)) + | Nat64Lit n -> SR.UnboxedWord64, compile_const_64 (Big_int.int64_of_big_int (nat64_to_int64 n)) | CharLit c -> SR.Vanilla, compile_unboxed_const Int32.(shift_left (of_int c) 8) | NullLit -> SR.Vanilla, Opt.null | TextLit t -> SR.Vanilla, Text.lit env t @@ -4384,6 +4401,10 @@ let compile_lit_as env sr_out lit = let sr_in, code = compile_lit env lit in code ^^ StackRep.adjust env sr_in sr_out +let prim_of_typ ty = match Type.normalize ty with + | Type.Prim ty -> ty + | _ -> assert false + let compile_unop env t op = let open Operator in match op, t with @@ -4397,13 +4418,34 @@ let compile_unop env t op = get_n ^^ G.i (Binary (Wasm.Values.I64 I64Op.Sub)) ) - | NegOp, Type.Prim Type.(Word8 | Word16 | Word32) -> + | NegOp, Type.(Prim Int64) -> + SR.UnboxedWord64, + Func.share_code1 env "neg_trap" ("n", I64Type) [I64Type] (fun env get_n -> + get_n ^^ + compile_const_64 0x8000000000000000L ^^ + G.i (Compare (Wasm.Values.I64 I64Op.Eq)) ^^ + E.then_trap_with env "arithmetic overflow" ^^ + compile_const_64 0L ^^ + get_n ^^ + G.i (Binary (Wasm.Values.I64 I64Op.Sub)) + ) + | NegOp, Type.(Prim (Word8 | Word16 | Word32)) -> StackRep.of_type t, Func.share_code1 env "neg32" ("n", I32Type) [I32Type] (fun env get_n -> compile_unboxed_zero ^^ get_n ^^ G.i (Binary (Wasm.Values.I32 I32Op.Sub)) ) + | NegOp, Type.(Prim (Int8 | Int16 | Int32)) -> + StackRep.of_type t, + Func.share_code1 env "neg32_trap" ("n", I32Type) [I32Type] (fun env get_n -> + get_n ^^ + compile_eq_const 0x80000000l ^^ + E.then_trap_with env "arithmetic overflow" ^^ + compile_unboxed_zero ^^ + get_n ^^ + G.i (Binary (Wasm.Values.I32 I32Op.Sub)) + ) | NotOp, Type.(Prim Word64) -> SR.UnboxedWord64, compile_const_64 (-1L) ^^ @@ -4472,7 +4514,7 @@ let rec compile_binop env t op = get_exp ^^ BigNum.compile_is_negative env ^^ E.then_trap_with env "negative power" ^^ get_n ^^ get_exp ^^ pow - | Type.(Prim Word64), PowOp -> BoxedWord.compile_unsigned_pow env + | Type.(Prim Word64), PowOp -> BoxedWord64.compile_unsigned_pow env | Type.(Prim Nat), PowOp -> BigNum.compile_unsigned_pow env | Type.(Prim Word64), AndOp -> G.i (Binary (Wasm.Values.I64 I64Op.And)) | Type.Prim Type.(Word8 | Word16 | Word32), AndOp -> G.i (Binary (Wasm.Values.I32 I32Op.And)) @@ -4516,28 +4558,31 @@ let rec compile_binop env t op = | _ -> todo_trap env "compile_binop" (Arrange_ops.binop op) ) -let compile_eq env t = match t with - | Type.Prim Type.Text -> Text.compare env - | Type.Prim Type.Bool -> G.i (Compare (Wasm.Values.I32 I32Op.Eq)) +let compile_eq env = function + | Type.(Prim Text) -> Text.compare env + | Type.(Prim Bool) -> G.i (Compare (Wasm.Values.I32 I32Op.Eq)) | Type.(Prim (Nat | Int)) -> BigNum.compile_eq env - | Type.(Prim Word64) -> G.i (Compare (Wasm.Values.I64 I64Op.Eq)) - | Type.(Prim (Word8 | Word16 | Word32 | Char)) -> G.i (Compare (Wasm.Values.I32 I32Op.Eq)) + | Type.(Prim (Int64 | Nat64 | Word64)) -> G.i (Compare (Wasm.Values.I64 I64Op.Eq)) + | Type.(Prim (Int8 | Nat8 | Word8 | Int16 | Nat16 | Word16 | Int32 | Nat32 | Word32 | Char)) -> + G.i (Compare (Wasm.Values.I32 I32Op.Eq)) | _ -> todo_trap env "compile_eq" (Arrange_ops.relop Operator.EqOp) let get_relops = Operator.(function - | GeOp -> Ge, I64Op.GeU, I32Op.GeU, I32Op.GeS - | GtOp -> Gt, I64Op.GtU, I32Op.GtU, I32Op.GtS - | LeOp -> Le, I64Op.LeU, I32Op.LeU, I32Op.LeS - | LtOp -> Lt, I64Op.LtU, I32Op.LtU, I32Op.LtS + | GeOp -> Ge, I64Op.GeU, I64Op.GeS, I32Op.GeU, I32Op.GeS + | GtOp -> Gt, I64Op.GtU, I64Op.GtS, I32Op.GtU, I32Op.GtS + | LeOp -> Le, I64Op.LeU, I64Op.LeS, I32Op.LeU, I32Op.LeS + | LtOp -> Lt, I64Op.LtU, I64Op.LtS, I32Op.LtU, I32Op.LtS | _ -> failwith "uncovered relop") let compile_comparison env t op = - let bigintop, u64op, u32op, s32op = get_relops op in + let bigintop, u64op, s64op, u32op, s32op = get_relops op in let open Type in match t with | Nat | Int -> BigNum.compile_relop env bigintop - | Word64 -> G.i (Compare (Wasm.Values.I64 u64op)) - | Word8 | Word16 | Word32 | Char -> G.i (Compare (Wasm.Values.I32 u32op)) + | Nat64 | Word64 -> G.i (Compare (Wasm.Values.I64 u64op)) + | Nat8 | Word8 | Nat16 | Word16 | Nat32 | Word32 | Char -> G.i (Compare (Wasm.Values.I32 u32op)) + | Int64 -> G.i (Compare (Wasm.Values.I64 s64op)) + | Int8 | Int16 | Int32 -> G.i (Compare (Wasm.Values.I32 s32op)) | _ -> todo_trap env "compile_comparison" (Arrange_type.prim t) let compile_relop env t op = @@ -4546,9 +4591,9 @@ let compile_relop env t op = match t, op with | _, EqOp -> compile_eq env t | _, NeqOp -> compile_eq env t ^^ - G.if_ (StackRep.to_block_type env SR.bool) (Bool.lit false) (Bool.lit true) - | Type.Prim Type.(Nat | Int | Word8 | Word16 | Word32 | Word64 | Char as t1), op1 -> - compile_comparison env t1 op1 + G.i (Test (Wasm.Values.I32 I32Op.Eqz)) + | Type.(Prim (Nat | Nat8 | Nat16 | Nat32 | Nat64 | Int | Int8 | Int16 | Int32 | Int64 | Word8 | Word16 | Word32 | Word64 | Char as t1)), op1 -> + compile_comparison env t1 op1 | _ -> todo_trap env "compile_relop" (Arrange_ops.relop op) (* compile_load_field implements the various “virtual fields”, which @@ -4670,43 +4715,120 @@ and compile_exp (env : E.t) ae exp = compile_exp_vanilla env ae e ^^ BigNum.to_word64 env + | "Nat64->Word64" + | "Int64->Word64" + | "Word64->Nat64" + | "Word64->Int64" + | "Nat32->Word32" + | "Int32->Word32" + | "Word32->Nat32" + | "Word32->Int32" + | "Nat16->Word16" + | "Int16->Word16" + | "Word16->Nat16" + | "Word16->Int16" + | "Nat8->Word8" + | "Int8->Word8" + | "Word8->Nat8" + | "Word8->Int8" -> + SR.Vanilla, + compile_exp_vanilla env ae e ^^ + G.nop + + | "Int->Int64" -> + SR.UnboxedWord64, + compile_exp_vanilla env ae e ^^ + Func.share_code1 env "Int->Int64" ("n", I32Type) [I64Type] (fun env get_n -> + get_n ^^ + BigNum.fits_signed_bits env 64 ^^ + E.else_trap_with env "losing precision" ^^ + get_n ^^ + BigNum.truncate_to_word64 env) + + | "Int->Int32" + | "Int->Int16" + | "Int->Int8" -> + let ty = exp.note.note_typ in + StackRep.of_type ty, + let pty = prim_of_typ ty in + compile_exp_vanilla env ae e ^^ + Func.share_code1 env (UnboxedSmallWord.name_of_type pty "Int->") ("n", I32Type) [I32Type] (fun env get_n -> + get_n ^^ + BigNum.fits_signed_bits env (UnboxedSmallWord.bits_of_type pty) ^^ + E.else_trap_with env "losing precision" ^^ + get_n ^^ + BigNum.truncate_to_word32 env ^^ + UnboxedSmallWord.msb_adjust pty) + + | "Nat->Nat64" -> + SR.UnboxedWord64, + compile_exp_vanilla env ae e ^^ + Func.share_code1 env "Nat->Nat64" ("n", I32Type) [I64Type] (fun env get_n -> + get_n ^^ + BigNum.fits_unsigned_bits env 64 ^^ + E.else_trap_with env "losing precision" ^^ + get_n ^^ + BigNum.truncate_to_word64 env) + + | "Nat->Nat32" + | "Nat->Nat16" + | "Nat->Nat8" -> + let ty = exp.note.note_typ in + StackRep.of_type ty, + let pty = prim_of_typ ty in + compile_exp_vanilla env ae e ^^ + Func.share_code1 env (UnboxedSmallWord.name_of_type pty "Nat->") ("n", I32Type) [I32Type] (fun env get_n -> + get_n ^^ + BigNum.fits_unsigned_bits env (UnboxedSmallWord.bits_of_type pty) ^^ + E.else_trap_with env "losing precision" ^^ + get_n ^^ + BigNum.truncate_to_word32 env ^^ + UnboxedSmallWord.msb_adjust pty) + | "Char->Word32" -> SR.UnboxedWord32, compile_exp_vanilla env ae e ^^ UnboxedSmallWord.unbox_codepoint + | "Nat8->Nat" | "Word8->Nat" -> SR.Vanilla, compile_exp_vanilla env ae e ^^ Prim.prim_shiftWordNtoUnsigned env (UnboxedSmallWord.shift_of_type Type.Word8) + | "Int8->Int" | "Word8->Int" -> SR.Vanilla, compile_exp_vanilla env ae e ^^ Prim.prim_shiftWordNtoSigned env (UnboxedSmallWord.shift_of_type Type.Word8) + | "Nat16->Nat" | "Word16->Nat" -> SR.Vanilla, compile_exp_vanilla env ae e ^^ Prim.prim_shiftWordNtoUnsigned env (UnboxedSmallWord.shift_of_type Type.Word16) + | "Int16->Int" | "Word16->Int" -> SR.Vanilla, compile_exp_vanilla env ae e ^^ Prim.prim_shiftWordNtoSigned env (UnboxedSmallWord.shift_of_type Type.Word16) + | "Nat32->Nat" | "Word32->Nat" -> SR.Vanilla, compile_exp_as env ae SR.UnboxedWord32 e ^^ Prim.prim_word32toNat env + | "Int32->Int" | "Word32->Int" -> SR.Vanilla, compile_exp_as env ae SR.UnboxedWord32 e ^^ Prim.prim_word32toInt env + | "Nat64->Nat" | "Word64->Nat" -> SR.Vanilla, compile_exp_as env ae SR.UnboxedWord64 e ^^ BigNum.from_word64 env - + | "Int64->Int" | "Word64->Int" -> SR.Vanilla, compile_exp_as env ae SR.UnboxedWord64 e ^^ @@ -5008,11 +5130,52 @@ and compile_lit_pat env l = | BoolLit true -> G.nop | BoolLit false -> - Bool.lit false ^^ - G.i (Compare (Wasm.Values.I32 I32Op.Eq)) + G.i (Test (Wasm.Values.I32 I32Op.Eqz)) | (NatLit _ | IntLit _) -> compile_lit_as env SR.Vanilla l ^^ BigNum.compile_eq env + | Nat8Lit _ -> + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Nat8) + | Nat16Lit _ -> + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Nat16) + | Nat32Lit _ -> + BoxedSmallWord.unbox env ^^ + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Nat32) + | Nat64Lit _ -> + BoxedWord64.unbox env ^^ + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Nat64) + | Int8Lit _ -> + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Int8) + | Int16Lit _ -> + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Int16) + | Int32Lit _ -> + BoxedSmallWord.unbox env ^^ + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Int32) + | Int64Lit _ -> + BoxedWord64.unbox env ^^ + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Int64) + | Word8Lit _ -> + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Word8) + | Word16Lit _ -> + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Word16) + | Word32Lit _ -> + BoxedSmallWord.unbox env ^^ + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Word32) + | Word64Lit _ -> + BoxedWord64.unbox env ^^ + snd (compile_lit env l) ^^ + compile_eq env Type.(Prim Word64) | (TextLit t) -> Text.lit env t ^^ Text.compare env diff --git a/src/interpreter/interpret.ml b/src/interpreter/interpret.ml index 6bcca1ef848..1131e0b1905 100644 --- a/src/interpreter/interpret.ml +++ b/src/interpreter/interpret.ml @@ -213,7 +213,15 @@ let interpret_lit env lit : V.value = | NullLit -> V.Null | BoolLit b -> V.Bool b | NatLit n -> V.Int n + | Nat8Lit n -> V.Nat8 n + | Nat16Lit n -> V.Nat16 n + | Nat32Lit n -> V.Nat32 n + | Nat64Lit n -> V.Nat64 n | IntLit i -> V.Int i + | Int8Lit i -> V.Int8 i + | Int16Lit i -> V.Int16 i + | Int32Lit i -> V.Int32 i + | Int64Lit i -> V.Int64 i | Word8Lit w -> V.Word8 w | Word16Lit w -> V.Word16 w | Word32Lit w -> V.Word32 w @@ -277,7 +285,9 @@ and interpret_exp_mut env exp (k : V.value V.cont) = | LitE lit -> k (interpret_lit env lit) | UnE (ot, op, exp1) -> - interpret_exp env exp1 (fun v1 -> k (Operator.unop !ot op v1)) + interpret_exp env exp1 + (fun v1 -> + k (try Operator.unop !ot op v1 with Invalid_argument s -> trap exp.at "%s" s)) | BinE (ot, exp1, op, exp2) -> interpret_exp env exp1 (fun v1 -> interpret_exp env exp2 (fun v2 -> @@ -346,13 +356,8 @@ and interpret_exp_mut env exp (k : V.value V.cont) = let call_conv, f = V.as_func v1 in check_call_conv exp1 call_conv; check_call_conv_arg env exp v2 call_conv; + last_region := exp.at; (* in case the following throws *) f v2 k -(* - try - let _, f = V.as_func v1 in f v2 k - with Invalid_argument s -> - trap exp.at "%s" s -*) ) ) | BlockE decs -> @@ -539,7 +544,15 @@ and match_lit lit v : bool = | NullLit, V.Null -> true | BoolLit b, V.Bool b' -> b = b' | NatLit n, V.Int n' -> V.Int.eq n n' + | Nat8Lit n, V.Nat8 n' -> V.Nat8.eq n n' + | Nat16Lit n, V.Nat16 n' -> V.Nat16.eq n n' + | Nat32Lit n, V.Nat32 n' -> V.Nat32.eq n n' + | Nat64Lit n, V.Nat64 n' -> V.Nat64.eq n n' | IntLit i, V.Int i' -> V.Int.eq i i' + | Int8Lit i, V.Int8 i' -> V.Int_8.eq i i' + | Int16Lit i, V.Int16 i' -> V.Int_16.eq i i' + | Int32Lit i, V.Int32 i' -> V.Int_32.eq i i' + | Int64Lit i, V.Int64 i' -> V.Int_64.eq i i' | Word8Lit w, V.Word8 w' -> w = w' | Word16Lit w, V.Word16 w' -> w = w' | Word32Lit w, V.Word32 w' -> w = w' @@ -720,7 +733,8 @@ let interpret_prog flags scope p : (V.value * scope) option = let vo = ref None in let ve = ref V.Env.empty in Scheduler.queue (fun () -> - interpret_block env p.it (Some ve) (fun v -> vo := Some v) + try interpret_block env p.it (Some ve) (fun v -> vo := Some v) + with Invalid_argument s -> trap !last_region "%s" s ); Scheduler.run (); let scope = { val_env = !ve; lib_env = scope.lib_env } in @@ -745,7 +759,7 @@ let interpret_library flags scope (filename, p) : scope = let v = match p.it with | [ { it = ExpD _ ; _ } ] -> Lib.Option.value !vo - (* HACK: to be remove once we restrict libraries to expressions *) + (* HACK: to be removed once we restrict libraries to expressions *) | ds -> V.Obj (V.Env.map Lib.Promise.value (!ve)) in diff --git a/src/ir_interpreter/interpret_ir.ml b/src/ir_interpreter/interpret_ir.ml index 04c4a43f456..796e3a25c96 100644 --- a/src/ir_interpreter/interpret_ir.ml +++ b/src/ir_interpreter/interpret_ir.ml @@ -235,7 +235,15 @@ let interpret_lit env lit : V.value = | NullLit -> V.Null | BoolLit b -> V.Bool b | NatLit n -> V.Int n + | Nat8Lit n -> V.Nat8 n + | Nat16Lit n -> V.Nat16 n + | Nat32Lit n -> V.Nat32 n + | Nat64Lit n -> V.Nat64 n | IntLit i -> V.Int i + | Int8Lit i -> V.Int8 i + | Int16Lit i -> V.Int16 i + | Int32Lit i -> V.Int32 i + | Int64Lit i -> V.Int64 i | Word8Lit w -> V.Word8 w | Word16Lit w -> V.Word16 w | Word32Lit w -> V.Word32 w @@ -293,7 +301,7 @@ and interpret_exp_mut env exp (k : V.value V.cont) = | LitE lit -> k (interpret_lit env lit) | UnE (ot, op, exp1) -> - interpret_exp env exp1 (fun v1 -> k (Operator.unop ot op v1)) + interpret_exp env exp1 (fun v1 -> k (try Operator.unop ot op v1 with Invalid_argument s -> trap exp.at "%s" s)) | ShowE (ot, exp1) -> interpret_exp env exp1 (fun v -> if Show.can_show ot @@ -349,18 +357,12 @@ and interpret_exp_mut env exp (k : V.value V.cont) = ) | CallE (_cc, exp1, typs, exp2) -> interpret_exp env exp1 (fun v1 -> - interpret_exp env exp2 (fun v2 -> - let call_conv, f = V.as_func v1 in - check_call_conv exp1 call_conv; - check_call_conv_arg env exp v2 call_conv; - f v2 k - -(* - try - let _, f = V.as_func v1 in f v2 k - with Invalid_argument s -> - trap exp.at "%s" s -*) + interpret_exp env exp2 (fun v2 -> + let call_conv, f = V.as_func v1 in + check_call_conv exp1 call_conv; + check_call_conv_arg env exp v2 call_conv; + last_region := exp.at; (* in case the following throws *) + f v2 k ) ) | BlockE (decs, exp1) -> @@ -537,7 +539,15 @@ and match_lit lit v : bool = | NullLit, V.Null -> true | BoolLit b, V.Bool b' -> b = b' | NatLit n, V.Int n' -> V.Int.eq n n' + | Nat8Lit n, V.Nat8 n' -> V.Nat8.eq n n' + | Nat16Lit n, V.Nat16 n' -> V.Nat16.eq n n' + | Nat32Lit n, V.Nat32 n' -> V.Nat32.eq n n' + | Nat64Lit n, V.Nat64 n' -> V.Nat64.eq n n' | IntLit i, V.Int i' -> V.Int.eq i i' + | Int8Lit i, V.Int8 i' -> V.Int_8.eq i i' + | Int16Lit i, V.Int16 i' -> V.Int_16.eq i i' + | Int32Lit i, V.Int32 i' -> V.Int_32.eq i i' + | Int64Lit i, V.Int64 i' -> V.Int_64.eq i i' | Word8Lit w, V.Word8 w' -> w = w' | Word16Lit w, V.Word16 w' -> w = w' | Word32Lit w, V.Word32 w' -> w = w' @@ -667,7 +677,8 @@ let interpret_prog flags scope ((ds, exp), flavor) : scope = let ve = ref V.Env.empty in try Scheduler.queue (fun () -> - interpret_block env (Some ve) ds exp (fun v -> ()) + try interpret_block env (Some ve) ds exp (fun v -> ()) + with Invalid_argument s -> trap !last_region "%s" s ); Scheduler.run (); !ve diff --git a/src/ir_passes/show.ml b/src/ir_passes/show.ml index 671508859ef..05beea657ca 100644 --- a/src/ir_passes/show.ml +++ b/src/ir_passes/show.ml @@ -277,6 +277,42 @@ let show_for : T.typ -> Ir.dec * T.typ list = fun t -> | T.Prim T.Int -> define_show t (invoke_prelude_show "@text_of_Int" t (argE t)), [] + | T.(Prim Nat8) -> + define_show t (invoke_prelude_show "@text_of_Nat8" t (argE t)), + [] + | T.(Prim Nat16) -> + define_show t (invoke_prelude_show "@text_of_Nat16" t (argE t)), + [] + | T.(Prim Nat32) -> + define_show t (invoke_prelude_show "@text_of_Nat32" t (argE t)), + [] + | T.(Prim Nat64) -> + define_show t (invoke_prelude_show "@text_of_Nat64" t (argE t)), + [] + | T.(Prim Int8) -> + define_show t (invoke_prelude_show "@text_of_Int8" t (argE t)), + [] + | T.(Prim Int16) -> + define_show t (invoke_prelude_show "@text_of_Int16" t (argE t)), + [] + | T.(Prim Int32) -> + define_show t (invoke_prelude_show "@text_of_Int32" t (argE t)), + [] + | T.(Prim Int64) -> + define_show t (invoke_prelude_show "@text_of_Int64" t (argE t)), + [] + | T.(Prim Word8) -> + define_show t (invoke_prelude_show "@text_of_Word8" t (argE t)), + [] + | T.(Prim Word16) -> + define_show t (invoke_prelude_show "@text_of_Word16" t (argE t)), + [] + | T.(Prim Word32) -> + define_show t (invoke_prelude_show "@text_of_Word32" t (argE t)), + [] + | T.(Prim Word64) -> + define_show t (invoke_prelude_show "@text_of_Word64" t (argE t)), + [] | T.Prim T.Text -> define_show t (invoke_prelude_show "@text_of_Text" t (argE t)), [] diff --git a/src/lowering/desugar.ml b/src/lowering/desugar.ml index bc416ccb6b1..cca1cf48e60 100644 --- a/src/lowering/desugar.ml +++ b/src/lowering/desugar.ml @@ -29,6 +29,10 @@ let apply_sign op l = Syntax.(match op, l with | PosOp, l -> l | NegOp, NatLit n -> NatLit (Value.Nat.sub Value.Nat.zero n) | NegOp, IntLit n -> IntLit (Value.Int.sub Value.Int.zero n) + | NegOp, Int8Lit n -> Int8Lit (Value.Int_8.sub Value.Int_8.zero n) + | NegOp, Int16Lit n -> Int16Lit (Value.Int_16.sub Value.Int_16.zero n) + | NegOp, Int32Lit n -> Int32Lit (Value.Int_32.sub Value.Int_32.zero n) + | NegOp, Int64Lit n -> Int64Lit (Value.Int_64.sub Value.Int_64.zero n) | _, _ -> raise (Invalid_argument "Invalid signed pattern") ) @@ -272,7 +276,15 @@ and lit l = match l with | S.NullLit -> I.NullLit | S.BoolLit x -> I.BoolLit x | S.NatLit x -> I.NatLit x + | S.Nat8Lit x -> I.Nat8Lit x + | S.Nat16Lit x -> I.Nat16Lit x + | S.Nat32Lit x -> I.Nat32Lit x + | S.Nat64Lit x -> I.Nat64Lit x | S.IntLit x -> I.IntLit x + | S.Int8Lit x -> I.Int8Lit x + | S.Int16Lit x -> I.Int16Lit x + | S.Int32Lit x -> I.Int32Lit x + | S.Int64Lit x -> I.Int64Lit x | S.Word8Lit x -> I.Word8Lit x | S.Word16Lit x -> I.Word16Lit x | S.Word32Lit x -> I.Word32Lit x diff --git a/src/prelude/prelude.ml b/src/prelude/prelude.ml index 17f4fb91013..cea163e645b 100644 --- a/src/prelude/prelude.ml +++ b/src/prelude/prelude.ml @@ -6,7 +6,15 @@ type Shared = prim "Shared"; type Null = prim "Null"; type Bool = prim "Bool"; type Nat = prim "Nat"; +type Nat8 = prim "Nat8"; +type Nat16 = prim "Nat16"; +type Nat32 = prim "Nat32"; +type Nat64 = prim "Nat64"; type Int = prim "Int"; +type Int8 = prim "Int8"; +type Int16 = prim "Int16"; +type Int32 = prim "Int32"; +type Int64 = prim "Int64"; type Word8 = prim "Word8"; type Word16 = prim "Word16"; type Word32 = prim "Word32"; @@ -58,6 +66,43 @@ func hashInt(x : Int) : Word32 { }; // Conversions + + +func int64ToInt(n : Int64) : Int = (prim "Int64->Int" : Int64 -> Int) n; +func intToInt64(n : Int) : Int64 = (prim "Int->Int64" : Int -> Int64) n; +func int64ToWord64(n : Int64) : Word64 = (prim "Int64->Word64" : Int64 -> Word64) n; +func word64ToInt64(n : Word64) : Int64 = (prim "Word64->Int64" : Word64 -> Int64) n; +func int32ToInt(n : Int32) : Int = (prim "Int32->Int" : Int32 -> Int) n; +func intToInt32(n : Int) : Int32 = (prim "Int->Int32" : Int -> Int32) n; +func int32ToWord32(n : Int32) : Word32 = (prim "Int32->Word32" : Int32 -> Word32) n; +func word32ToInt32(n : Word32) : Int32 = (prim "Word32->Int32" : Word32 -> Int32) n; +func int16ToInt(n : Int16) : Int = (prim "Int16->Int" : Int16 -> Int) n; +func intToInt16(n : Int) : Int16 = (prim "Int->Int16" : Int -> Int16) n; +func int16ToWord16(n : Int16) : Word16 = (prim "Int16->Word16" : Int16 -> Word16) n; +func word16ToInt16(n : Word16) : Int16 = (prim "Word16->Int16" : Word16 -> Int16) n; +func int8ToInt(n : Int8) : Int = (prim "Int8->Int" : Int8 -> Int) n; +func intToInt8(n : Int) : Int8 = (prim "Int->Int8" : Int -> Int8) n; +func int8ToWord8(n : Int8) : Word8 = (prim "Int8->Word8" : Int8 -> Word8) n; +func word8ToInt8(n : Word8) : Int8 = (prim "Word8->Int8" : Word8 -> Int8) n; + +func nat64ToNat(n : Nat64) : Nat = (prim "Nat64->Nat" : Nat64 -> Nat) n; +func natToNat64(n : Nat) : Nat64 = (prim "Nat->Nat64" : Nat -> Nat64) n; +func nat64ToWord64(n : Nat64) : Word64 = (prim "Nat64->Word64" : Nat64 -> Word64) n; +func word64ToNat64(n : Word64) : Nat64 = (prim "Word64->Nat64" : Word64 -> Nat64) n; +func nat32ToNat(n : Nat32) : Nat = (prim "Nat32->Nat" : Nat32 -> Nat) n; +func natToNat32(n : Nat) : Nat32 = (prim "Nat->Nat32" : Nat -> Nat32) n; +func nat32ToWord32(n : Nat32) : Word32 = (prim "Nat32->Word32" : Nat32 -> Word32) n; +func word32ToNat32(n : Word32) : Nat32 = (prim "Word32->Nat32" : Word32 -> Nat32) n; +func nat16ToNat(n : Nat16) : Nat = (prim "Nat16->Nat" : Nat16 -> Nat) n; +func natToNat16(n : Nat) : Nat16 = (prim "Nat->Nat16" : Nat -> Nat16) n; +func nat16ToWord16(n : Nat16) : Word16 = (prim "Nat16->Word16" : Nat16 -> Word16) n; +func word16ToNat16(n : Word16) : Nat16 = (prim "Word16->Nat16" : Word16 -> Nat16) n; +func nat8ToNat(n : Nat8) : Nat = (prim "Nat8->Nat" : Nat8 -> Nat) n; +func natToNat8(n : Nat) : Nat8 = (prim "Nat->Nat8" : Nat -> Nat8) n; +func nat8ToWord8(n : Nat8) : Word8 = (prim "Nat8->Word8" : Nat8 -> Word8) n; +func word8ToNat8(n : Word8) : Nat8 = (prim "Word8->Nat8" : Word8 -> Nat8) n; + + func natToWord8(n : Nat) : Word8 = (prim "Nat->Word8" : Nat -> Word8) n; func word8ToNat(n : Word8) : Nat = (prim "Word8->Nat" : Word8 -> Nat) n; func intToWord8(n : Int) : Word8 = (prim "Int->Word8" : Int -> Word8) n; @@ -141,6 +186,20 @@ func @text_of_Int(x : Int) : Text { } }; +func @text_of_Nat8(x : Nat8) : Text = @text_of_Nat (nat8ToNat x); +func @text_of_Nat16(x : Nat16) : Text = @text_of_Nat (nat16ToNat x); +func @text_of_Nat32(x : Nat32) : Text = @text_of_Nat (nat32ToNat x); +func @text_of_Nat64(x : Nat64) : Text = @text_of_Nat (nat64ToNat x); +func @text_of_Int8(x : Int8) : Text = @text_of_Int (int8ToInt x); +func @text_of_Int16(x : Int16) : Text = @text_of_Int (int16ToInt x); +func @text_of_Int32(x : Int32) : Text = @text_of_Int (int32ToInt x); +func @text_of_Int64(x : Int64) : Text = @text_of_Int (int64ToInt x); +func @text_of_Word8(x : Word8) : Text = @text_of_Nat (word8ToNat x); +func @text_of_Word16(x : Word16) : Text = @text_of_Nat (word16ToNat x); +func @text_of_Word32(x : Word32) : Text = @text_of_Nat (word32ToNat x); +func @text_of_Word64(x : Word64) : Text = @text_of_Nat (word64ToNat x); + + func @text_of_Bool(b : Bool) : Text { if (b) "true" else "false" }; diff --git a/test/fail/ok/outrange-int64lower.run-ir.ok b/test/fail/ok/outrange-int64lower.run-ir.ok new file mode 100644 index 00000000000..d3ac87f6451 --- /dev/null +++ b/test/fail/ok/outrange-int64lower.run-ir.ok @@ -0,0 +1 @@ +prelude:71.36-71.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int64lower.run-low.ok b/test/fail/ok/outrange-int64lower.run-low.ok new file mode 100644 index 00000000000..d3ac87f6451 --- /dev/null +++ b/test/fail/ok/outrange-int64lower.run-low.ok @@ -0,0 +1 @@ +prelude:71.36-71.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int64lower.run.ok b/test/fail/ok/outrange-int64lower.run.ok new file mode 100644 index 00000000000..d3ac87f6451 --- /dev/null +++ b/test/fail/ok/outrange-int64lower.run.ok @@ -0,0 +1 @@ +prelude:71.36-71.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int64lower.wasm-run.ok b/test/fail/ok/outrange-int64lower.wasm-run.ok new file mode 100644 index 00000000000..a87edfdf573 --- /dev/null +++ b/test/fail/ok/outrange-int64lower.wasm-run.ok @@ -0,0 +1 @@ +_out/outrange-int64lower.wasm:0x___: runtime trap: unreachable executed diff --git a/test/fail/ok/outrange-int64negation.run-ir.ok b/test/fail/ok/outrange-int64negation.run-ir.ok new file mode 100644 index 00000000000..01c2fd0b1c4 --- /dev/null +++ b/test/fail/ok/outrange-int64negation.run-ir.ok @@ -0,0 +1 @@ +outrange-int64negation.as:1.9-1.33: execution error, value out of bounds diff --git a/test/fail/ok/outrange-int64negation.run-low.ok b/test/fail/ok/outrange-int64negation.run-low.ok new file mode 100644 index 00000000000..01c2fd0b1c4 --- /dev/null +++ b/test/fail/ok/outrange-int64negation.run-low.ok @@ -0,0 +1 @@ +outrange-int64negation.as:1.9-1.33: execution error, value out of bounds diff --git a/test/fail/ok/outrange-int64negation.run.ok b/test/fail/ok/outrange-int64negation.run.ok new file mode 100644 index 00000000000..01c2fd0b1c4 --- /dev/null +++ b/test/fail/ok/outrange-int64negation.run.ok @@ -0,0 +1 @@ +outrange-int64negation.as:1.9-1.33: execution error, value out of bounds diff --git a/test/fail/ok/outrange-int64negation.wasm-run.ok b/test/fail/ok/outrange-int64negation.wasm-run.ok new file mode 100644 index 00000000000..4db5b575d1b --- /dev/null +++ b/test/fail/ok/outrange-int64negation.wasm-run.ok @@ -0,0 +1 @@ +_out/outrange-int64negation.wasm:0x___: runtime trap: unreachable executed diff --git a/test/fail/ok/outrange-int64upper.run-ir.ok b/test/fail/ok/outrange-int64upper.run-ir.ok new file mode 100644 index 00000000000..d3ac87f6451 --- /dev/null +++ b/test/fail/ok/outrange-int64upper.run-ir.ok @@ -0,0 +1 @@ +prelude:71.36-71.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int64upper.run-low.ok b/test/fail/ok/outrange-int64upper.run-low.ok new file mode 100644 index 00000000000..d3ac87f6451 --- /dev/null +++ b/test/fail/ok/outrange-int64upper.run-low.ok @@ -0,0 +1 @@ +prelude:71.36-71.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int64upper.run.ok b/test/fail/ok/outrange-int64upper.run.ok new file mode 100644 index 00000000000..d3ac87f6451 --- /dev/null +++ b/test/fail/ok/outrange-int64upper.run.ok @@ -0,0 +1 @@ +prelude:71.36-71.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int64upper.wasm-run.ok b/test/fail/ok/outrange-int64upper.wasm-run.ok new file mode 100644 index 00000000000..6ec234a4e85 --- /dev/null +++ b/test/fail/ok/outrange-int64upper.wasm-run.ok @@ -0,0 +1 @@ +_out/outrange-int64upper.wasm:0x___: runtime trap: unreachable executed diff --git a/test/fail/ok/outrange-int8lower.run-ir.ok b/test/fail/ok/outrange-int8lower.run-ir.ok new file mode 100644 index 00000000000..e0fee3eba79 --- /dev/null +++ b/test/fail/ok/outrange-int8lower.run-ir.ok @@ -0,0 +1 @@ +prelude:83.34-83.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int8lower.run-low.ok b/test/fail/ok/outrange-int8lower.run-low.ok new file mode 100644 index 00000000000..e0fee3eba79 --- /dev/null +++ b/test/fail/ok/outrange-int8lower.run-low.ok @@ -0,0 +1 @@ +prelude:83.34-83.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int8lower.run.ok b/test/fail/ok/outrange-int8lower.run.ok new file mode 100644 index 00000000000..e0fee3eba79 --- /dev/null +++ b/test/fail/ok/outrange-int8lower.run.ok @@ -0,0 +1 @@ +prelude:83.34-83.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int8lower.wasm-run.ok b/test/fail/ok/outrange-int8lower.wasm-run.ok new file mode 100644 index 00000000000..054470b6319 --- /dev/null +++ b/test/fail/ok/outrange-int8lower.wasm-run.ok @@ -0,0 +1 @@ +_out/outrange-int8lower.wasm:0x___: runtime trap: unreachable executed diff --git a/test/fail/ok/outrange-int8upper.run-ir.ok b/test/fail/ok/outrange-int8upper.run-ir.ok new file mode 100644 index 00000000000..e0fee3eba79 --- /dev/null +++ b/test/fail/ok/outrange-int8upper.run-ir.ok @@ -0,0 +1 @@ +prelude:83.34-83.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int8upper.run-low.ok b/test/fail/ok/outrange-int8upper.run-low.ok new file mode 100644 index 00000000000..e0fee3eba79 --- /dev/null +++ b/test/fail/ok/outrange-int8upper.run-low.ok @@ -0,0 +1 @@ +prelude:83.34-83.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int8upper.run.ok b/test/fail/ok/outrange-int8upper.run.ok new file mode 100644 index 00000000000..e0fee3eba79 --- /dev/null +++ b/test/fail/ok/outrange-int8upper.run.ok @@ -0,0 +1 @@ +prelude:83.34-83.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-int8upper.wasm-run.ok b/test/fail/ok/outrange-int8upper.wasm-run.ok new file mode 100644 index 00000000000..2d769f0989f --- /dev/null +++ b/test/fail/ok/outrange-int8upper.wasm-run.ok @@ -0,0 +1 @@ +_out/outrange-int8upper.wasm:0x___: runtime trap: unreachable executed diff --git a/test/fail/ok/outrange-nat64.run-ir.ok b/test/fail/ok/outrange-nat64.run-ir.ok new file mode 100644 index 00000000000..72676577d7c --- /dev/null +++ b/test/fail/ok/outrange-nat64.run-ir.ok @@ -0,0 +1 @@ +prelude:88.36-88.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-nat64.run-low.ok b/test/fail/ok/outrange-nat64.run-low.ok new file mode 100644 index 00000000000..72676577d7c --- /dev/null +++ b/test/fail/ok/outrange-nat64.run-low.ok @@ -0,0 +1 @@ +prelude:88.36-88.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-nat64.run.ok b/test/fail/ok/outrange-nat64.run.ok new file mode 100644 index 00000000000..72676577d7c --- /dev/null +++ b/test/fail/ok/outrange-nat64.run.ok @@ -0,0 +1 @@ +prelude:88.36-88.72: execution error, numeric overflow diff --git a/test/fail/ok/outrange-nat64.wasm-run.ok b/test/fail/ok/outrange-nat64.wasm-run.ok new file mode 100644 index 00000000000..c2173dffda9 --- /dev/null +++ b/test/fail/ok/outrange-nat64.wasm-run.ok @@ -0,0 +1 @@ +_out/outrange-nat64.wasm:0x___: runtime trap: unreachable executed diff --git a/test/fail/ok/outrange-nat8.run-ir.ok b/test/fail/ok/outrange-nat8.run-ir.ok new file mode 100644 index 00000000000..1767cb22299 --- /dev/null +++ b/test/fail/ok/outrange-nat8.run-ir.ok @@ -0,0 +1 @@ +prelude:100.34-100.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-nat8.run-low.ok b/test/fail/ok/outrange-nat8.run-low.ok new file mode 100644 index 00000000000..1767cb22299 --- /dev/null +++ b/test/fail/ok/outrange-nat8.run-low.ok @@ -0,0 +1 @@ +prelude:100.34-100.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-nat8.run.ok b/test/fail/ok/outrange-nat8.run.ok new file mode 100644 index 00000000000..1767cb22299 --- /dev/null +++ b/test/fail/ok/outrange-nat8.run.ok @@ -0,0 +1 @@ +prelude:100.34-100.68: execution error, numeric overflow diff --git a/test/fail/ok/outrange-nat8.wasm-run.ok b/test/fail/ok/outrange-nat8.wasm-run.ok new file mode 100644 index 00000000000..e64bc25b4c7 --- /dev/null +++ b/test/fail/ok/outrange-nat8.wasm-run.ok @@ -0,0 +1 @@ +_out/outrange-nat8.wasm:0x___: runtime trap: unreachable executed diff --git a/test/fail/outrange-int64lower.as b/test/fail/outrange-int64lower.as new file mode 100644 index 00000000000..a9a6a6625e8 --- /dev/null +++ b/test/fail/outrange-int64lower.as @@ -0,0 +1 @@ +let _ = intToInt64 (- 2 ** 63 - 1); diff --git a/test/fail/outrange-int64negation.as b/test/fail/outrange-int64negation.as new file mode 100644 index 00000000000..bfa832e02f9 --- /dev/null +++ b/test/fail/outrange-int64negation.as @@ -0,0 +1 @@ +let _ = - intToInt64 (- 2 ** 63); // this should trap diff --git a/test/fail/outrange-int64upper.as b/test/fail/outrange-int64upper.as new file mode 100644 index 00000000000..1c87d142031 --- /dev/null +++ b/test/fail/outrange-int64upper.as @@ -0,0 +1 @@ +let _ = intToInt64 (2 ** 63); diff --git a/test/fail/outrange-int8lower.as b/test/fail/outrange-int8lower.as new file mode 100644 index 00000000000..9cd498631cb --- /dev/null +++ b/test/fail/outrange-int8lower.as @@ -0,0 +1 @@ +let _ = intToInt8 (-129); diff --git a/test/fail/outrange-int8upper.as b/test/fail/outrange-int8upper.as new file mode 100644 index 00000000000..95fc54f289a --- /dev/null +++ b/test/fail/outrange-int8upper.as @@ -0,0 +1 @@ +let _ = intToInt8 128; diff --git a/test/fail/outrange-nat64.as b/test/fail/outrange-nat64.as new file mode 100644 index 00000000000..5fc78dd9b38 --- /dev/null +++ b/test/fail/outrange-nat64.as @@ -0,0 +1 @@ +let _ = natToNat64 (2 ** 64); diff --git a/test/fail/outrange-nat8.as b/test/fail/outrange-nat8.as new file mode 100644 index 00000000000..cfce83df95f --- /dev/null +++ b/test/fail/outrange-nat8.as @@ -0,0 +1 @@ +let _ = natToNat8 256 diff --git a/test/repl/ok/outrange-int-nat.stdout.ok b/test/repl/ok/outrange-int-nat.stdout.ok new file mode 100644 index 00000000000..daa7c921fa1 --- /dev/null +++ b/test/repl/ok/outrange-int-nat.stdout.ok @@ -0,0 +1,34 @@ +ActorScript 0.1 interpreter +> 127 : Int8 +> prelude:83.34-83.68: execution error, numeric overflow +> -128 : Int8 +> prelude:83.34-83.68: execution error, numeric overflow +> 32_767 : Int16 +> prelude:79.36-79.72: execution error, numeric overflow +> -32_768 : Int16 +> prelude:79.36-79.72: execution error, numeric overflow +> 2_147_483_647 : Int32 +> prelude:75.36-75.72: execution error, numeric overflow +> -2_147_483_648 : Int32 +> prelude:75.36-75.72: execution error, numeric overflow +> 9_223_372_036_854_775_807 : Int64 +> prelude:71.36-71.72: execution error, numeric overflow +> -9_223_372_036_854_775_808 : Int64 +> prelude:71.36-71.72: execution error, numeric overflow +> 255 : Nat8 +> prelude:100.34-100.68: execution error, numeric overflow +> 65_535 : Nat16 +> prelude:96.36-96.72: execution error, numeric overflow +> 4_294_967_295 : Nat32 +> prelude:92.36-92.72: execution error, numeric overflow +> 18_446_744_073_709_551_615 : Nat64 +> prelude:88.36-88.72: execution error, numeric overflow +> -127 : Int8 +> -127 : Int8 +> -32_767 : Int16 +> -32_767 : Int16 +> -2_147_483_647 : Int32 +> -2_147_483_647 : Int32 +> -9_223_372_036_854_775_807 : Int64 +> -9_223_372_036_854_775_807 : Int64 +> diff --git a/test/repl/outrange-int-nat.sh b/test/repl/outrange-int-nat.sh new file mode 100755 index 00000000000..8554b134278 --- /dev/null +++ b/test/repl/outrange-int-nat.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Tests that the repl Int* and Nat* types properly trap +${ASC:-$(dirname "$BASH_SOURCE")/../../src/asc} -i <<__END__ +intToInt8 0x7F; +intToInt8 0x80; +intToInt8 (-0x80); +intToInt8 (-0x81); + +intToInt16 0x7FFF; +intToInt16 0x8000; +intToInt16 (-0x8000); +intToInt16 (-0x8001); + +intToInt32 0x7FFFFFFF; +intToInt32 0x80000000; +intToInt32 (-0x80000000); +intToInt32 (-0x80000001); + +intToInt64 0x7FFFFFFFFFFFFFFF; +intToInt64 0x8000000000000000; +intToInt64 (-0x8000000000000000); +intToInt64 (-0x8000000000000001); + + +natToNat8 0xFF; +natToNat8 0x100; + +natToNat16 0xFFFF; +natToNat16 0x10000; + +natToNat32 0xFFFFFFFF; +natToNat32 0x100000000; + +natToNat64 0xFFFFFFFFFFFFFFFF; +natToNat64 0x10000000000000000; + + +-127 : Int8; +-0x7F : Int8; +-32767 : Int16; +-0x7FFF : Int16; +-2147483647 : Int32; +-0x7FFFFFFF : Int32; +-9223372036854775807 : Int64; +-0x7FFFFFFFFFFFFFFF : Int64; + +__END__ diff --git a/test/run-dfinity/data-params.as b/test/run-dfinity/data-params.as index 68207c6323d..b2c1eadbcfd 100644 --- a/test/run-dfinity/data-params.as +++ b/test/run-dfinity/data-params.as @@ -61,13 +61,30 @@ let a = actor { printInt(c); print("\n"); }; - incwords(w16 : Word16, w32 : Word32, w64 : Word64) : () { + incwords(w8 : Word8, w16 : Word16, w32 : Word32, w64 : Word64) : () { + c += word8ToInt(w8); c += word16ToInt(w16); c += word32ToInt(w32); c += word64ToInt(w64); printInt(c); print("\n"); }; + incnats(n8 : Nat8, n16 : Nat16, n32 : Nat32, n64 : Nat64) : () { + c += nat8ToNat(n8); + c += nat16ToNat(n16); + c += nat32ToNat(n32); + c += nat64ToNat(n64); + printInt(c); + print("\n"); + }; + incints(i8 : Int8, i16 : Int16, i32 : Int32, i64 : Int64) : () { + c += int8ToInt(i8); + c += int16ToInt(i16); + c += int32ToInt(i32); + c += int64ToInt(i64); + printInt(c); + print("\n"); + }; }; @@ -92,8 +109,10 @@ a.printLabeledOpt(?"Foo2: "); a.incn(10000000000000); a.inci(10000000000000); a.inci(-20000000000000); -a.incwords(1,2,3); -a.incwords(-1,-2,-3); +a.incwords(1,2,3,4); +a.incwords(-1,-2,-3,-4); +a.incnats(1,2,3,4); +a.incints(1,2,3,4);//(-1,-2,-3,-4); a.incn(2**100); a.inci(2**100); a.inci(-(2**101)); diff --git a/test/run-dfinity/ok/data-params.dvm-run.ok b/test/run-dfinity/ok/data-params.dvm-run.ok index b59714f09cc..f32875d2100 100644 --- a/test/run-dfinity/ok/data-params.dvm-run.ok +++ b/test/run-dfinity/ok/data-params.dvm-run.ok @@ -19,8 +19,10 @@ Foo2: 1006211 10000001006211 20000001006211 1006211 -1006217 -1006211 -1267650600228229401496704211587 -2535301200456458802993407416963 +1006221 1006211 +1006221 +1006231 +1267650600228229401496704211607 +2535301200456458802993407416983 +1006231 diff --git a/test/run-dfinity/ok/data-params.run-ir.ok b/test/run-dfinity/ok/data-params.run-ir.ok index e4cd9453940..19fd485396a 100644 --- a/test/run-dfinity/ok/data-params.run-ir.ok +++ b/test/run-dfinity/ok/data-params.run-ir.ok @@ -20,8 +20,10 @@ Foo2: 1006211 10000001006211 20000001006211 1006211 -1006217 -1006211 -1267650600228229401496704211587 -2535301200456458802993407416963 +1006221 1006211 +1006221 +1006231 +1267650600228229401496704211607 +2535301200456458802993407416983 +1006231 diff --git a/test/run-dfinity/ok/data-params.run-low.ok b/test/run-dfinity/ok/data-params.run-low.ok index e4cd9453940..19fd485396a 100644 --- a/test/run-dfinity/ok/data-params.run-low.ok +++ b/test/run-dfinity/ok/data-params.run-low.ok @@ -20,8 +20,10 @@ Foo2: 1006211 10000001006211 20000001006211 1006211 -1006217 -1006211 -1267650600228229401496704211587 -2535301200456458802993407416963 +1006221 1006211 +1006221 +1006231 +1267650600228229401496704211607 +2535301200456458802993407416983 +1006231 diff --git a/test/run-dfinity/ok/data-params.run.ok b/test/run-dfinity/ok/data-params.run.ok index e4cd9453940..19fd485396a 100644 --- a/test/run-dfinity/ok/data-params.run.ok +++ b/test/run-dfinity/ok/data-params.run.ok @@ -20,8 +20,10 @@ Foo2: 1006211 10000001006211 20000001006211 1006211 -1006217 -1006211 -1267650600228229401496704211587 -2535301200456458802993407416963 +1006221 1006211 +1006221 +1006231 +1267650600228229401496704211607 +2535301200456458802993407416983 +1006231 diff --git a/test/run-dfinity/ok/show.dvm-run.ok b/test/run-dfinity/ok/show.dvm-run.ok index d48b386b82f..819767efd2e 100644 --- a/test/run-dfinity/ok/show.dvm-run.ok +++ b/test/run-dfinity/ok/show.dvm-run.ok @@ -15,7 +15,10 @@ false [1, 2, 3] [var 1, 2, 3] {bar = true; foo = 42} -{bar = true; foo = 42} (#foo) (#bar 42) (#foo 42) +42 +42 +42 +-42 diff --git a/test/run-dfinity/ok/show.run-ir.ok b/test/run-dfinity/ok/show.run-ir.ok index d48b386b82f..819767efd2e 100644 --- a/test/run-dfinity/ok/show.run-ir.ok +++ b/test/run-dfinity/ok/show.run-ir.ok @@ -15,7 +15,10 @@ false [1, 2, 3] [var 1, 2, 3] {bar = true; foo = 42} -{bar = true; foo = 42} (#foo) (#bar 42) (#foo 42) +42 +42 +42 +-42 diff --git a/test/run-dfinity/ok/show.run-low.ok b/test/run-dfinity/ok/show.run-low.ok index d48b386b82f..819767efd2e 100644 --- a/test/run-dfinity/ok/show.run-low.ok +++ b/test/run-dfinity/ok/show.run-low.ok @@ -15,7 +15,10 @@ false [1, 2, 3] [var 1, 2, 3] {bar = true; foo = 42} -{bar = true; foo = 42} (#foo) (#bar 42) (#foo 42) +42 +42 +42 +-42 diff --git a/test/run-dfinity/ok/show.run.ok b/test/run-dfinity/ok/show.run.ok index d48b386b82f..819767efd2e 100644 --- a/test/run-dfinity/ok/show.run.ok +++ b/test/run-dfinity/ok/show.run.ok @@ -15,7 +15,10 @@ false [1, 2, 3] [var 1, 2, 3] {bar = true; foo = 42} -{bar = true; foo = 42} (#foo) (#bar 42) (#foo 42) +42 +42 +42 +-42 diff --git a/test/run-dfinity/show.as b/test/run-dfinity/show.as index 779b9aa0d5e..8f9ca5619a7 100644 --- a/test/run-dfinity/show.as +++ b/test/run-dfinity/show.as @@ -17,7 +17,10 @@ printLn(debug_show ([1,2,3])); printLn(debug_show ([var 1,2,3])); class Foo() { let foo : Int = 42; var bar : Bool = true ; private hidden = [1,2] }; printLn(debug_show (Foo())); -printLn(debug_show (Foo())); printLn(debug_show (#foo ())); printLn(debug_show (#bar 42)); printLn(debug_show ((#foo 42): {#foo : Int; #bar : Text})); +printLn(debug_show (42 : Word16)); +printLn(debug_show (42 : Nat8)); +printLn(debug_show (42 : Int32)); +printLn(debug_show (intToInt64 (-42))); diff --git a/test/run/conversions.as b/test/run/conversions.as index d1a53c2045d..17f3297accb 100644 --- a/test/run/conversions.as +++ b/test/run/conversions.as @@ -21,36 +21,70 @@ assert(word32ToNat 42 == 42); assert(word32ToNat 2147483647 == 2147483647); // 2**31 - 1 assert(word32ToNat 4294967295 == 4294967295); // 2**32 - 1 +func forall (f : T -> (), l : [T]) = for (e in l.vals()) { f e }; + { func roundtrip(n : Nat) = assert (word32ToNat (natToWord32 n) == n); - roundtrip 0; - roundtrip 10; - roundtrip 100; - roundtrip 1000; - roundtrip 10000; - roundtrip 100000; - roundtrip 1000000; - roundtrip 10000000; - roundtrip 100000000; - roundtrip 1000000000; - roundtrip 0x7FFFFFFF; - roundtrip 0xFFFFFFFF; + forall(roundtrip, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF]); }; { func roundtrip(w : Word32) = assert (natToWord32 (word32ToNat w) == w); - roundtrip 0; - roundtrip 10; - roundtrip 100; - roundtrip 1000; - roundtrip 10000; - roundtrip 100000; - roundtrip 1000000; - roundtrip 10000000; - roundtrip 100000000; - roundtrip 1000000000; - roundtrip 0x7FFFFFFF; - roundtrip 0xFFFFFFFF; + forall(roundtrip, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF]); + + + + func roundtripNat64(w : Word64) = assert (nat64ToWord64 (word64ToNat64 w) == w); + forall(roundtripNat64, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF]); + + func roundtripInt64(w : Word64) = assert (int64ToWord64 (word64ToInt64 w) == w); + forall(roundtripInt64, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF]); + + func roundtrip64i(w : Int) = assert (int64ToInt (intToInt64 w) == w); + forall(roundtrip64i, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0x7FFFFFFFFFFFFFFF]); + forall(roundtrip64i, [-10, -100, -1000, -10000, -100000, -1000000, -10000000, -100000000, -1000000000, -2147483648, -9223372036854775808]); + func roundtrip64n(w : Nat) = assert (nat64ToNat (natToNat64 w) == w); + forall(roundtrip64n, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF]); + + + + func roundtripNat32(w : Word32) = assert (nat32ToWord32 (word32ToNat32 w) == w); + forall(roundtripNat32, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF]); + + func roundtripInt32(w : Word32) = assert (int32ToWord32 (word32ToInt32 w) == w); + forall(roundtripInt32, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF]); + + func roundtrip32i(w : Int) = assert (int32ToInt (intToInt32 w) == w); + forall(roundtrip32i, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF]); + forall(roundtrip32i, [-10, -100, -1000, -10000, -100000, -1000000, -10000000, -100000000, -1000000000, -2147483648]); + func roundtrip32n(w : Nat) = assert (nat32ToNat (natToNat32 w) == w); + forall(roundtrip32n, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF]); + + + func roundtripNat16(w : Word16) = assert (nat16ToWord16 (word16ToNat16 w) == w); + forall(roundtripNat16, [0, 10, 100, 1000, 10000, 0xFFFF]); + + func roundtripInt16(w : Word16) = assert (int16ToWord16 (word16ToInt16 w) == w); + forall(roundtripInt16, [0, 10, 100, 1000, 10000, 0xFFFF]); + + func roundtrip16i(w : Int) = assert (int16ToInt (intToInt16 w) == w); + forall(roundtrip16i, [0, 10, 100, 1000, 10000, 0x7FFF]); + forall(roundtrip16i, [-10, -100, -1000, -10000, -32768]); + func roundtrip16n(w : Nat) = assert (nat16ToNat (natToNat16 w) == w); + forall(roundtrip16n, [0, 10, 100, 1000, 10000, 0xFFFF]); + + + func roundtripNat8(w : Word8) = assert (nat8ToWord8 (word8ToNat8 w) == w); + forall(roundtripNat8, [0, 10, 100, 0xFF]); + + func roundtripInt8(w : Word8) = assert (int8ToWord8 (word8ToInt8 w) == w); + forall(roundtripInt8, [0, 10, 100, 0xFF]); + + func roundtrip8i(w : Int) = assert (int8ToInt (intToInt8 w) == w); + forall(roundtrip8i, [0, 10, 100, 0x7F]); + forall(roundtrip8i, [-10, -100, -128]); + func roundtrip8n(w : Nat) = assert (nat8ToNat (natToNat8 w) == w); + forall(roundtrip8n, [0, 10, 100, 0xFF]); }; @@ -93,55 +127,17 @@ println(word32ToInt 4294967295); // == (-1) // 2**32 - 1 { func roundtrip(i : Int) = assert (word32ToInt (intToWord32 i) == i); - roundtrip 0; - roundtrip 10; - roundtrip 100; - roundtrip 1000; - roundtrip 10000; - roundtrip 100000; - roundtrip 1000000; - roundtrip 10000000; - roundtrip 100000000; - roundtrip 1000000000; - roundtrip 0x7FFFFFFF; - - roundtrip (-10); - roundtrip (-100); - roundtrip (-1000); - roundtrip (-10000); - roundtrip (-100000); - roundtrip (-1000000); - roundtrip (-10000000); - roundtrip (-100000000); - roundtrip (-1000000000); - roundtrip (-2147483648); + forall(roundtrip, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF]); + + forall(roundtrip, [-10, -100, -1000, -10000, -100000, -1000000, -10000000, -100000000, -1000000000, -2147483648]); }; { func roundtrip(w : Word32) = assert (intToWord32 (word32ToInt w) == w); - roundtrip 0; - roundtrip 10; - roundtrip 100; - roundtrip 1000; - roundtrip 10000; - roundtrip 100000; - roundtrip 1000000; - roundtrip 10000000; - roundtrip 100000000; - roundtrip 1000000000; - roundtrip 0x7FFFFFFF; - roundtrip 0xFFFFFFFF; - - /*!*/ - roundtrip (-10); - roundtrip (-100); - roundtrip (-1000); - roundtrip (-10000); - roundtrip (-100000); - roundtrip (-1000000); - roundtrip (-10000000); - roundtrip (-100000000); - roundtrip (-1000000000); + forall(roundtrip, [0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0x7FFFFFFF, 0xFFFFFFFF]); + + /* non-canonical range for Word32 */ + forall(roundtrip, [-10, -100, -1000, -10000, -100000, -1000000, -10000000, -100000000, -1000000000]); }; @@ -157,14 +153,7 @@ assert(charToWord32 '\u{10ffff}' == (0x10FFFF : Word32)); { func roundtrip(w : Word32) = assert (charToWord32 (word32ToChar w) == w); - roundtrip 0; - roundtrip 10; - roundtrip 100; - roundtrip 1000; - roundtrip 10000; - roundtrip 100000; - roundtrip 1000000; - roundtrip 0x10FFFF; // largest code point + forall(roundtrip, [0, 10, 100, 1000, 10000, 100000, 1000000, 0x10FFFF]); // largest code point }; diff --git a/test/run/numeric-ops.as b/test/run/numeric-ops.as index 923a82c0c1b..67cfa38a61f 100644 --- a/test/run/numeric-ops.as +++ b/test/run/numeric-ops.as @@ -208,3 +208,51 @@ func testWord64(a : Word64, b : Word64) : [Word64] { verify([3, 18_446_744_073_709_551_613, 8, 18_446_744_073_709_551_614, 15, 0, 3, 243], testWord64(3, 5), func (a : Word64, b : Word64) : Bool = a == b); + + +func testInt64(a : Int64, b : Int64) : [Int64] { + let pos1 = + a; + let pos2 = (+ a) : Int64; + let neg1 = - a; + let neg2 = (- a) : Int64; + /*let sum1 = a + b; + let sum2 = (a + b) : Int64; + let diff1 = a - b; + let diff2 = (a - b) : Int64; + let prod1 = a * b; + let prod2 = (a * b) : Int64; + let rat1 = a / b; + let rat2 = (a / b) : Int64; + let mod1 = a % b; + let mod2 = (a % b) : Int64; + let pow1 = a ** b; + let pow2 = (a ** b) : Int64;*/ + [pos1, pos2, neg1, neg2, /*sum1, sum2, diff1, diff2, prod1, prod2, rat1, rat2, mod1, mod2, pow1, pow2*/] +}; + +verify([3, -3/*, 8, 18_446_744_073_709_551_614, 15, 0, 3, 243*/], testInt64(3, 5), + func (a : Int64, b : Int64) : Bool = a == b); + + +func testInt8(a : Int8, b : Int8) : [Int8] { + let pos1 = + a; + let pos2 = (+ a) : Int8; + let neg1 = - a; + let neg2 = (- a) : Int8; + /*let sum1 = a + b; + let sum2 = (a + b) : Int8; + let diff1 = a - b; + let diff2 = (a - b) : Int8; + let prod1 = a * b; + let prod2 = (a * b) : Int8; + let rat1 = a / b; + let rat2 = (a / b) : Int8; + let mod1 = a % b; + let mod2 = (a % b) : Int8; + let pow1 = a ** b; + let pow2 = (a ** b) : Int8;*/ + [pos1, pos2, neg1, neg2, /*sum1, sum2, diff1, diff2, prod1, prod2, rat1, rat2, mod1, mod2, pow1, pow2*/] +}; + +verify([3, -3/*, 8, -2, 15, 0, 3, 243*/], testInt8(3, 5), + func (a : Int8, b : Int8) : Bool = a == b); diff --git a/test/run/ranged-nums.as b/test/run/ranged-nums.as new file mode 100644 index 00000000000..5c8e270db51 --- /dev/null +++ b/test/run/ranged-nums.as @@ -0,0 +1,47 @@ +let _ = 255 : Nat8; +let _ = 65535 : Nat16; +let _ = 4_294_967_295 : Nat32; +let _ = 18_446_744_073_709_551_615 : Nat64; + + +let _ = 127 : Int8; +let _ = 32767 : Int16; +let _ = 2_147_483_647 : Int32; +let _ = 9_223_372_036_854_775_807 : Int64; + + +// TODO(gabor) below limits are off-by one, as explained +// in the open issue in #487. +let _ = -127 : Int8; +let _ = -32767 : Int16; +let _ = -2_147_483_647 : Int32; +let _ = -9_223_372_036_854_775_807 : Int64; + +// test patterns + +func n8 (n : Nat8) = assert (switch n { case 0 false; case 1 false; case 42 true; case _ false }); +func n16 (n : Nat16) = assert (switch n { case 0 false; case 1 false; case 65000 true; case _ false }); +func n32 (n : Nat32) = assert (switch n { case 0 false; case 1 false; case 4_294_967_295 true; case _ false }); +func n64 (n : Nat64) = assert (switch n { case 0 false; case 1 false; case 42 true; case _ false }); + + +n8 42; +n16 65000; +n32 4_294_967_295; +n64 42; + + +func i8 (n : Int8) = assert (switch n { case 0 false; case (-42) true; case 1 false; case 42 true; case _ false }); +func i16 (n : Int16) = assert (switch n { case 0 false; case (-32000) true; case 1 false; case 32000 true; case _ false }); +func i32 (n : Int32) = assert (switch n { case 0 false; case (-20000000) true; case 1 false; case 1_294_967_295 true; case _ false }); +func i64 (n : Int64) = assert (switch n { case 0 false; case (-420000000000) true; case 1 false; case 42 true; case _ false }); + + +i8 42; +i8 (-42); +i16 32000; +i16 (-32000); +i32 1_294_967_295; +i32 (-20000000); +i64 (-420000000000); +i64 42; diff --git a/test/run/words.as b/test/run/words.as index d2b9be2ec41..eb9f0444769 100644 --- a/test/run/words.as +++ b/test/run/words.as @@ -276,3 +276,17 @@ func checkpointJuliett() {}; assert (3 : Word8 ** (4 : Word8) == (81 : Word8)); assert (3 : Word8 ** (5 : Word8) == (243 : Word8)); }; + + +// check whether patterns work + +func w8 (n : Word8) = assert (switch n { case 0 false; case 1 false; case 42 true; case _ false }); +func w16 (n : Word16) = assert (switch n { case 0 false; case 1 false; case 65000 true; case _ false }); +func w32 (n : Word32) = assert (switch n { case 0 false; case 1 false; case 4_294_967_295 true; case _ false }); +func w64 (n : Word64) = assert (switch n { case 0 false; case 1 false; case 42 true; case _ false }); + + +w8 42; +w16 65000; +w32 4_294_967_295; +w64 42;