diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e3a35..e693f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Added the `[a..b]` language construct, returning the list of numbers between + `a` and `b` (inclusive). Returns the empty list if `a` > `b`. ### Changed ### Removed diff --git a/priv/stdlib/ListInternal.aes b/priv/stdlib/ListInternal.aes index efd61ac..7d6773a 100644 --- a/priv/stdlib/ListInternal.aes +++ b/priv/stdlib/ListInternal.aes @@ -7,3 +7,10 @@ namespace ListInternal = [] => [] x :: xs => f(x) ++ flat_map(f, xs) + // -- From..to --------------------------------------------------------------- + + function from_to(a : int, b : int) : list(int) = from_to_(a, b, []) + + private function from_to_(a, b, acc) = + if (a > b) acc else from_to_(a, b - 1, b :: acc) + diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 6993768..482bd16 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -1352,6 +1352,9 @@ infer_infix({RelOp, As}) T = fresh_uvar(As), %% allow any type here, check in ast_to_icode that we have comparison for it Bool = {id, As, "bool"}, {fun_t, As, [], [T, T], Bool}; +infer_infix({'..', As}) -> + Int = {id, As, "int"}, + {fun_t, As, [], [Int, Int], {app_t, As, {id, As, "list"}, [Int]}}; infer_infix({'::', As}) -> ElemType = fresh_uvar(As), ListType = {app_t, As, {id, As, "list"}, [ElemType]}, diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 0b83908..16fe99e 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -453,12 +453,16 @@ expr_to_fcode(Env, _Type, {list, _, Es}) -> lists:foldr(fun(E, L) -> {op, '::', [expr_to_fcode(Env, E), L]} end, nil, Es); +expr_to_fcode(Env, _Type, {app, _, {'..', _}, [A, B]}) -> + {def_u, FromTo, _} = resolve_fun(Env, ["ListInternal", "from_to"]), + {def, FromTo, [expr_to_fcode(Env, A), expr_to_fcode(Env, B)]}; + expr_to_fcode(Env, _Type, {list_comp, _, Yield, []}) -> {op, '::', [expr_to_fcode(Env, Yield), nil]}; expr_to_fcode(Env, _Type, {list_comp, As, Yield, [{comprehension_bind, {typed, {id, _, Arg}, _}, BindExpr}|Rest]}) -> Env1 = bind_var(Env, Arg), Bind = {lam, [Arg], expr_to_fcode(Env1, {list_comp, As, Yield, Rest})}, - {def_u, FlatMap, _} = resolve_fun(Env, ["List", "flat_map"]), + {def_u, FlatMap, _} = resolve_fun(Env, ["ListInternal", "flat_map"]), {def, FlatMap, [Bind, expr_to_fcode(Env, BindExpr)]}; expr_to_fcode(Env, Type, {list_comp, As, Yield, [{comprehension_if, _, Cond}|Rest]}) -> make_if(expr_to_fcode(Env, Cond), diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index 7b0c839..ca1433a 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -523,6 +523,10 @@ ast_body({app, _, {typed, _, {con, _, Name}, _}, Args}, Icode) -> ast_body({app, _, {typed, _, {qcon, _, Name}, _}, Args}, Icode) -> Tag = aeso_icode:get_constructor_tag(Name, Icode), #tuple{cpts = [#integer{value = Tag} | [ ast_body(Arg, Icode) || Arg <- Args ]]}; +ast_body({app, _, {'..', _}, [A, B]}, Icode) -> + #funcall + { function = #var_ref{ name = ["ListInternal", "from_to"] } + , args = [ast_body(A, Icode), ast_body(B, Icode)] }; ast_body({app,As,Fun,Args}, Icode) -> case aeso_syntax:get_ann(format, As) of infix -> @@ -541,7 +545,7 @@ ast_body({list_comp, _, Yield, []}, Icode) -> #list{elems = [ast_body(Yield, Icode)]}; ast_body({list_comp, As, Yield, [{comprehension_bind, {typed, Arg, ArgType}, BindExpr}|Rest]}, Icode) -> #funcall - { function = #var_ref{ name = ["List", "flat_map"] } + { function = #var_ref{ name = ["ListInternal", "flat_map"] } , args = [ #lambda{ args=[#arg{name = ast_id(Arg), type = ast_type(ArgType, Icode)}] , body = ast_body({list_comp, As, Yield, Rest}, Icode)