From d8bf0bda45938bf4c9e94aede1f3c3166982ebc5 Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Fri, 25 Jan 2019 12:49:11 +0100 Subject: [PATCH 1/5] Remove integer bit operations --- src/aeso_ast_infer_types.erl | 6 ++---- src/aeso_ast_to_icode.erl | 3 --- src/aeso_parser.erl | 6 +++--- src/aeso_pretty.erl | 8 +------- src/aeso_scan.erl | 3 +-- src/aeso_syntax.erl | 4 ++-- test/contracts/all_syntax.aes | 2 -- test/contracts/operators.aes | 7 ------- 8 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index cfeb08e..7bbe6b4 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -691,8 +691,7 @@ infer_infix({BoolOp, As}) {fun_t, As, [], [Bool,Bool], Bool}; infer_infix({IntOp, As}) when IntOp == '+'; IntOp == '-'; IntOp == '*'; IntOp == '/'; - IntOp == '^'; IntOp == 'mod'; IntOp == 'bsl'; IntOp == 'bsr'; - IntOp == 'band'; IntOp == 'bor'; IntOp == 'bxor' -> + IntOp == '^'; IntOp == 'mod' -> Int = {id, As, "int"}, {fun_t, As, [], [Int, Int], Int}; infer_infix({RelOp, As}) @@ -714,8 +713,7 @@ infer_infix({'++', As}) -> infer_prefix({'!',As}) -> Bool = {id, As, "bool"}, {fun_t, As, [], [Bool], Bool}; -infer_prefix({IntOp,As}) - when IntOp =:= '-'; IntOp =:= 'bnot' -> +infer_prefix({IntOp,As}) when IntOp =:= '-' -> Int = {id, As, "int"}, {fun_t, As, [], [Int], Int}. diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index 0509847..9f90550 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -526,9 +526,6 @@ ast_binop(Op, Ann, {typed, _, A, Type}, B, Icode) ast_binop('++', _, A, B, Icode) -> #funcall{ function = #var_ref{ name = {builtin, list_concat} }, args = [ast_body(A, Icode), ast_body(B, Icode)] }; -%% Bit shift operations takes their arguments backwards!? -ast_binop(Op, _, A, B, Icode) when Op =:= 'bsl'; Op =:= 'bsr' -> - #binop{op = Op, right = ast_body(A, Icode), left = ast_body(B, Icode)}; ast_binop(Op, _, A, B, Icode) -> #binop{op = Op, left = ast_body(A, Icode), right = ast_body(B, Icode)}. diff --git a/src/aeso_parser.erl b/src/aeso_parser.erl index f84295e..57c61cf 100644 --- a/src/aeso_parser.erl +++ b/src/aeso_parser.erl @@ -176,11 +176,11 @@ expr200() -> infixr(expr300(), binop('||')). expr300() -> infixr(expr400(), binop('&&')). expr400() -> infix(expr500(), binop(['<', '>', '=<', '>=', '==', '!='])). expr500() -> infixr(expr600(), binop(['::', '++'])). -expr600() -> infixl(expr650(), binop(['+', '-', 'bor', 'bxor', 'bsr', 'bsl'])). +expr600() -> infixl(expr650(), binop(['+', '-'])). expr650() -> ?RULE(many(token('-')), expr700(), prefixes(_1, _2)). -expr700() -> infixl(expr750(), binop(['*', '/', mod, 'band'])). +expr700() -> infixl(expr750(), binop(['*', '/', mod])). expr750() -> infixl(expr800(), binop(['^'])). -expr800() -> ?RULE(many(choice(token('!'), token('bnot'))), expr900(), prefixes(_1, _2)). +expr800() -> ?RULE(many(token('!')), expr900(), prefixes(_1, _2)). expr900() -> ?RULE(exprAtom(), many(elim()), elim(_1, _2)). exprAtom() -> diff --git a/src/aeso_pretty.erl b/src/aeso_pretty.erl index 3462a2e..f9209dd 100644 --- a/src/aeso_pretty.erl +++ b/src/aeso_pretty.erl @@ -359,20 +359,14 @@ bin_prec('++') -> {500, 600, 500}; bin_prec('::') -> {500, 600, 500}; bin_prec('+') -> {600, 600, 650}; bin_prec('-') -> {600, 600, 650}; -bin_prec('bor') -> {600, 600, 650}; -bin_prec('bxor') -> {600, 600, 650}; -bin_prec('bsl') -> {600, 600, 650}; -bin_prec('bsr') -> {600, 600, 650}; bin_prec('*') -> {700, 700, 750}; bin_prec('/') -> {700, 700, 750}; bin_prec(mod) -> {700, 700, 750}; -bin_prec('band') -> {700, 700, 750}; bin_prec('^') -> {750, 750, 800}. -spec un_prec(aeso_syntax:un_op()) -> {integer(), integer()}. un_prec('-') -> {650, 650}; -un_prec('!') -> {800, 800}; -un_prec('bnot') -> {800, 800}. +un_prec('!') -> {800, 800}. equals(Ann, A, B) -> {app, [{format, infix} | Ann], {'=', Ann}, [A, B]}. diff --git a/src/aeso_scan.erl b/src/aeso_scan.erl index 5cee063..17f4153 100644 --- a/src/aeso_scan.erl +++ b/src/aeso_scan.erl @@ -37,8 +37,7 @@ lexer() -> , {"[^/*]+|[/*]", skip()} ], Keywords = ["contract", "import", "let", "rec", "switch", "type", "record", "datatype", "if", "elif", "else", "function", - "stateful", "true", "false", "and", "mod", "public", "private", "indexed", "internal", - "band", "bor", "bxor", "bsl", "bsr", "bnot"], + "stateful", "true", "false", "and", "mod", "public", "private", "indexed", "internal"], KW = string:join(Keywords, "|"), Rules = diff --git a/src/aeso_syntax.erl b/src/aeso_syntax.erl index 5767e82..f8dc364 100644 --- a/src/aeso_syntax.erl +++ b/src/aeso_syntax.erl @@ -75,10 +75,10 @@ -type op() :: bin_op() | un_op(). --type bin_op() :: '+' | '-' | '*' | '/' | mod | '^' | 'band' | 'bor' | 'bsl' | 'bsr' | 'bxor' +-type bin_op() :: '+' | '-' | '*' | '/' | mod | '^' | '++' | '::' | '<' | '>' | '=<' | '>=' | '==' | '!=' | '||' | '&&' | '..'. --type un_op() :: '-' | '!' | 'bnot'. +-type un_op() :: '-' | '!'. -type expr() :: {lam, ann(), [arg()], expr()} diff --git a/test/contracts/all_syntax.aes b/test/contracts/all_syntax.aes index b3ac623..4b80311 100644 --- a/test/contracts/all_syntax.aes +++ b/test/contracts/all_syntax.aes @@ -36,8 +36,6 @@ contract AllSyntax = (x, [y, z]) => bar({x = z, y = -y + - -z * (-1)}) (x, y :: _) => () - function bitOperations(x, y) = bnot (0xff00 band x bsl 4 bxor 0xa5a5a5 bsr 4 bor y) - function mutual() = let rec recFun(x : int) = mutFun(x) and mutFun(x) = if(x =< 0) 1 else x * recFun(x - 1) diff --git a/test/contracts/operators.aes b/test/contracts/operators.aes index 9ac89fb..1363a6c 100644 --- a/test/contracts/operators.aes +++ b/test/contracts/operators.aes @@ -1,5 +1,4 @@ // - + * / mod arithmetic operators -// bnot band bor bxor bsl bsr bitwise operators // ! && || logical operators // == != < > =< >= comparison operators // :: ++ list operators @@ -13,12 +12,6 @@ contract Operators = "/" => a / b "mod" => a mod b "^" => a ^ b - "bnot" => bnot a - "band" => a band b - "bor" => a bor b - "bxor" => a bxor b - "bsl" => a bsl b - "bsr" => a bsr b function bool_op(a : bool, b : bool, op : string) = switch(op) From a367d5040a09f8052a56156e9470c93794ece7fe Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Fri, 25 Jan 2019 13:34:28 +0100 Subject: [PATCH 2/5] Add builtin bit field type --- src/aeso_ast_infer_types.erl | 7 +++++++ src/aeso_ast_to_icode.erl | 24 ++++++++++++++++++++++++ src/aeso_builtins.erl | 12 ++++++++++++ src/aeso_icode.erl | 1 + test/contracts/multi_sig.aes | 28 +++++++++++++--------------- 5 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 7bbe6b4..dcfdfb1 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -79,6 +79,7 @@ global_env() -> Event = {id, Ann, "event"}, State = {id, Ann, "state"}, Hash = {id, Ann, "hash"}, + Bits = {id, Ann, "bits"}, Oracle = fun(Q, R) -> {app_t, Ann, {id, Ann, "oracle"}, [Q, R]} end, Query = fun(Q, R) -> {app_t, Ann, {id, Ann, "oracle_query"}, [Q, R]} end, Unit = {tuple_t, Ann, []}, @@ -159,6 +160,12 @@ global_env() -> {["String", "sha3"], Fun1(String, Hash)}, {["String", "sha256"], Fun1(String, Hash)}, {["String", "blake2b"], Fun1(String, Hash)}, + %% Bits + {["Bits", "set"], Fun([Bits, Int], Bits)}, + {["Bits", "clear"], Fun([Bits, Int], Bits)}, + {["Bits", "test"], Fun([Bits, Int], Bool)}, + {["Bits", "sum"], Fun1(Bits, Int)}, + {["Bits", "zero"], Bits}, %% Conversion {["Int", "to_str"], Fun1(Int, String)}, {["Address", "to_str"], Fun1(Address, String)} diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index 9f90550..023fd42 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -348,6 +348,30 @@ ast_body(?qid_app(["String", "concat"], [String1, String2], _, _), Icode) -> ast_body(?qid_app(["String", "sha3"], [String], _, _), Icode) -> #unop{ op = 'sha3', rand = ast_body(String, Icode) }; +%% -- Bits +ast_body(?qid_app(["Bits", "test"], [Bits, Ix], _, _), Icode) -> + %% (Bits bsr Ix) band 1 + #binop{ op = 'band' + , left = #binop{ op = 'bsr', left = ast_body(Ix, Icode), right = ast_body(Bits, Icode) } + , right = #integer{ value = 1 } }; +ast_body(?qid_app(["Bits", "set"], [Bits, Ix], _, _), Icode) -> + %% Bits bor (1 bsl Ix) + #binop{ op = 'bor' + , left = ast_body(Bits, Icode) + , right = #binop{ op = 'bsl', left = ast_body(Ix, Icode), right = #integer{ value = 1 } } }; +ast_body(?qid_app(["Bits", "clear"], [Bits, Ix], _, _), Icode) -> + %% Bits band (bnot (1 bsl Ix)) + #binop{ op = 'band' + , left = ast_body(Bits, Icode) + , right = #unop{ op = 'bnot' + , rand = #binop{ op = 'bsl' + , left = ast_body(Ix, Icode) + , right = #integer{ value = 1 } } } }; +ast_body({qid, _, ["Bits", "zero"]}, _Icode) -> + #integer{ value = 0 }; +ast_body(?qid_app(["Bits", "sum"], [Bits], _, _), Icode) -> + builtin_call(popcount, [ast_body(Bits, Icode), #integer{ value = 0 }]); + %% -- Conversion ast_body(?qid_app(["Int", "to_str"], [Int], _, _), Icode) -> builtin_call(int_to_str, [ast_body(Int, Icode)]); diff --git a/src/aeso_builtins.erl b/src/aeso_builtins.erl index 0b44692..383fcf4 100644 --- a/src/aeso_builtins.erl +++ b/src/aeso_builtins.erl @@ -148,6 +148,7 @@ builtin_function(BF) -> string_shift_copy -> bfun(BF, builtin_string_shift_copy()); str_equal_p -> bfun(BF, builtin_str_equal_p()); str_equal -> bfun(BF, builtin_str_equal()); + popcount -> bfun(BF, builtin_popcount()); int_to_str -> bfun(BF, builtin_int_to_str()); addr_to_str -> bfun(BF, builtin_addr_to_str()); {baseX_int, X} -> bfun(BF, builtin_baseX_int(X)); @@ -398,6 +399,17 @@ builtin_str_equal() -> )), word}. +%% Count the number of 1s in a bit field. +builtin_popcount() -> + %% function popcount(bits, acc) = + %% if (bits == 0) acc + %% else popcount(bits bsr 1, acc + bits band 1) + {[{"bits", word}, {"acc", word}], + {ifte, ?EQ(bits, 0), + ?V(acc), + ?call(popcount, [op('bsr', 1, bits), ?ADD(acc, op('band', bits, 1))]) + }, word}. + builtin_int_to_str() -> {[{"i", word}], ?call({baseX_int, 10}, [?V(i)]), word}. diff --git a/src/aeso_icode.erl b/src/aeso_icode.erl index 33fcc56..8ee3839 100644 --- a/src/aeso_icode.erl +++ b/src/aeso_icode.erl @@ -59,6 +59,7 @@ builtin_types() -> Word = fun([]) -> word end, #{ "bool" => Word , "int" => Word + , "bits" => Word , "string" => fun([]) -> string end , "address" => Word , "hash" => Word diff --git a/test/contracts/multi_sig.aes b/test/contracts/multi_sig.aes index 6c8c9ff..028b621 100644 --- a/test/contracts/multi_sig.aes +++ b/test/contracts/multi_sig.aes @@ -5,7 +5,7 @@ contract MultiSig = - record pending_state = { yetNeeded : uint, ownersDone : uint, index : uint } + record pending_state = { yetNeeded : int, ownersDone : bits, index : int } datatype event = Confirmation (address, hash) // of { .owner : Address, .operation : Hash } @@ -13,18 +13,18 @@ contract MultiSig = | OwnerChanged (address, address) // of { .oldOwner : Address, .newOwner : Address } | OwnerAdded (address) // of { .newOwner : Address } | OwnerRemoved (address) // of { .removedOwner : Address } - | ReqChanged (uint) // of { .newReq : uint } + | ReqChanged (int) // of { .newReq : int } - let maxOwners : uint = 250 + let maxOwners : int = 250 - record state = { nRequired : uint - , nOwners : uint - , owners : map(uint, address) - , ownerIndex : map(address, uint) + record state = { nRequired : int + , nOwners : int + , owners : map(int, address) + , ownerIndex : map(address, int) , pending : map(hash, pending_state) , pendingIndex : list(address) } - function init (owners : list(address), nRequired : uint) : state = + function init (owners : list(address), nRequired : int) : state = let n = length(owners) + 1 { nRequired = nRequired, nOwners = n, @@ -39,10 +39,9 @@ contract MultiSig = function revoke(operation : hash) = let ownerIx = lookup(state.ownerIndex, caller()) let pending = lookup(state.pendingIndex, operation) - let ownerIxBit = 1 bsl (ownerIx - 1) - let _ = require(pending.ownersDone band ownerIxBit > 0) + let _ = require(Bits.test(pending.ownersDone, ownerIx)) let pending' = pending { yetNeeded = pending.yetNeeded + 1 - , ownersDone = pending.ownersDone - ownerIxBit } + , ownersDone = Bits.clear(pending.ownersDone, ownerIx - 1) } put(state{ pendingIndex.operator = pending' }) event(Revoke(caller, operation)) @@ -91,7 +90,7 @@ contract MultiSig = , pendingIx = [] }, event = [OwnerRemoved(oldOwner)] } - function changeRequirement(newReq : uint) = + function changeRequirement(newReq : int) = let _ = require(newReq =< state.nOwners) switch(check_pending(callhash())) CheckFail(state') => { state = state' } @@ -102,7 +101,7 @@ contract MultiSig = event = [ReqChanged(newReq)] } - function getOwner(ownerIx0 : uint) = + function getOwner(ownerIx0 : int) = lookup(state.owners, ownerIx0 + 1) function isOwner(owner : address) = @@ -116,8 +115,7 @@ contract MultiSig = Some(pending) => let _ = require(isOwner(owner)) let ownerIx = lookup(state.ownerIndex, owner) - let ownerIxBit = 1 bsl (ownerIx - 1) - (pending.ownersDone band ownerIxBit) != 0 + Bits.test(pending.ownersDone, ownerIx - 1) /* Leave the rest for now... */ From 9c77622c7c6e25a6badb1b3045989a70127f229d Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Fri, 25 Jan 2019 14:10:12 +0100 Subject: [PATCH 3/5] Add set operations on bit fields (union, isect, diff) --- src/aeso_ast_infer_types.erl | 3 +++ src/aeso_ast_to_icode.erl | 37 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index dcfdfb1..154e617 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -165,6 +165,9 @@ global_env() -> {["Bits", "clear"], Fun([Bits, Int], Bits)}, {["Bits", "test"], Fun([Bits, Int], Bool)}, {["Bits", "sum"], Fun1(Bits, Int)}, + {["Bits", "intersection"], Fun([Bits, Bits], Bits)}, + {["Bits", "union"], Fun([Bits, Bits], Bits)}, + {["Bits", "difference"], Fun([Bits, Bits], Bits)}, {["Bits", "zero"], Bits}, %% Conversion {["Int", "to_str"], Fun1(Int, String)}, diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index 023fd42..b9fb28f 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -349,24 +349,25 @@ ast_body(?qid_app(["String", "sha3"], [String], _, _), Icode) -> #unop{ op = 'sha3', rand = ast_body(String, Icode) }; %% -- Bits -ast_body(?qid_app(["Bits", "test"], [Bits, Ix], _, _), Icode) -> - %% (Bits bsr Ix) band 1 - #binop{ op = 'band' - , left = #binop{ op = 'bsr', left = ast_body(Ix, Icode), right = ast_body(Bits, Icode) } - , right = #integer{ value = 1 } }; -ast_body(?qid_app(["Bits", "set"], [Bits, Ix], _, _), Icode) -> - %% Bits bor (1 bsl Ix) - #binop{ op = 'bor' - , left = ast_body(Bits, Icode) - , right = #binop{ op = 'bsl', left = ast_body(Ix, Icode), right = #integer{ value = 1 } } }; -ast_body(?qid_app(["Bits", "clear"], [Bits, Ix], _, _), Icode) -> - %% Bits band (bnot (1 bsl Ix)) - #binop{ op = 'band' - , left = ast_body(Bits, Icode) - , right = #unop{ op = 'bnot' - , rand = #binop{ op = 'bsl' - , left = ast_body(Ix, Icode) - , right = #integer{ value = 1 } } } }; +ast_body(?qid_app(["Bits", Fun], Args, _, _), Icode) + when Fun == "test"; Fun == "set"; Fun == "clear"; + Fun == "union"; Fun == "intersection"; Fun == "difference" -> + C = fun(N) when is_integer(N) -> #integer{ value = N }; + (AST) -> ast_body(AST, Icode) end, + Bin = fun(O) -> fun(A, B) -> #binop{ op = O, left = C(A), right = C(B) } end end, + And = Bin('band'), + Or = Bin('bor'), + Bsl = fun(A, B) -> (Bin('bsl'))(B, A) end, %% flipped arguments + Bsr = fun(A, B) -> (Bin('bsr'))(B, A) end, + Neg = fun(A) -> #unop{ op = 'bnot', rand = C(A) } end, + case [Fun | Args] of + ["test", Bits, Ix] -> And(Bsr(Bits, Ix), 1); + ["set", Bits, Ix] -> Or(Bits, Bsl(1, Ix)); + ["clear", Bits, Ix] -> And(Bits, Neg(Bsl(1, Ix))); + ["union", A, B] -> Or(A, B); + ["intersection", A, B] -> And(A, B); + ["difference", A, B] -> And(A, Neg(And(A, B))) + end; ast_body({qid, _, ["Bits", "zero"]}, _Icode) -> #integer{ value = 0 }; ast_body(?qid_app(["Bits", "sum"], [Bits], _, _), Icode) -> From 3e1290efafc9f37869fdac9292b4e638b000fd8b Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Fri, 25 Jan 2019 14:12:23 +0100 Subject: [PATCH 4/5] Add Bits.all and rename Bits.zero to Bits.none --- src/aeso_ast_infer_types.erl | 3 ++- src/aeso_ast_to_icode.erl | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 154e617..76e8d62 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -168,7 +168,8 @@ global_env() -> {["Bits", "intersection"], Fun([Bits, Bits], Bits)}, {["Bits", "union"], Fun([Bits, Bits], Bits)}, {["Bits", "difference"], Fun([Bits, Bits], Bits)}, - {["Bits", "zero"], Bits}, + {["Bits", "none"], Bits}, + {["Bits", "all"], Bits}, %% Conversion {["Int", "to_str"], Fun1(Int, String)}, {["Address", "to_str"], Fun1(Address, String)} diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index b9fb28f..a3a55aa 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -368,8 +368,10 @@ ast_body(?qid_app(["Bits", Fun], Args, _, _), Icode) ["intersection", A, B] -> And(A, B); ["difference", A, B] -> And(A, Neg(And(A, B))) end; -ast_body({qid, _, ["Bits", "zero"]}, _Icode) -> +ast_body({qid, _, ["Bits", "none"]}, _Icode) -> #integer{ value = 0 }; +ast_body({qid, _, ["Bits", "all"]}, _Icode) -> + #integer{ value = -1 }; ast_body(?qid_app(["Bits", "sum"], [Bits], _, _), Icode) -> builtin_call(popcount, [ast_body(Bits, Icode), #integer{ value = 0 }]); From 79de25b3a5f22db37aa716c8663dae0715896531 Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Fri, 25 Jan 2019 15:03:52 +0100 Subject: [PATCH 5/5] Fix minor bugs in compilation of bit fields --- src/aeso_ast_to_icode.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index a3a55aa..2e00104 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -353,14 +353,14 @@ ast_body(?qid_app(["Bits", Fun], Args, _, _), Icode) when Fun == "test"; Fun == "set"; Fun == "clear"; Fun == "union"; Fun == "intersection"; Fun == "difference" -> C = fun(N) when is_integer(N) -> #integer{ value = N }; - (AST) -> ast_body(AST, Icode) end, + (X) -> X end, Bin = fun(O) -> fun(A, B) -> #binop{ op = O, left = C(A), right = C(B) } end end, And = Bin('band'), Or = Bin('bor'), Bsl = fun(A, B) -> (Bin('bsl'))(B, A) end, %% flipped arguments Bsr = fun(A, B) -> (Bin('bsr'))(B, A) end, Neg = fun(A) -> #unop{ op = 'bnot', rand = C(A) } end, - case [Fun | Args] of + case [Fun | [ ast_body(Arg, Icode) || Arg <- Args ]] of ["test", Bits, Ix] -> And(Bsr(Bits, Ix), 1); ["set", Bits, Ix] -> Or(Bits, Bsl(1, Ix)); ["clear", Bits, Ix] -> And(Bits, Neg(Bsl(1, Ix))); @@ -371,7 +371,7 @@ ast_body(?qid_app(["Bits", Fun], Args, _, _), Icode) ast_body({qid, _, ["Bits", "none"]}, _Icode) -> #integer{ value = 0 }; ast_body({qid, _, ["Bits", "all"]}, _Icode) -> - #integer{ value = -1 }; + #integer{ value = 1 bsl 256 - 1 }; ast_body(?qid_app(["Bits", "sum"], [Bits], _, _), Icode) -> builtin_call(popcount, [ast_body(Bits, Icode), #integer{ value = 0 }]);