@@ -102,6 +102,9 @@ class SimpleElaborator : public BaseNodeReplacementVisitor {
102102 return maybe_macro;
103103 }
104104 }
105+
106+ // Implementing a few common functions. Getting out of hand to do this
107+ // inline here. Think of breaking them out.
105108 const std::string_view fun_name = f->identifier ()->id ();
106109 if (fun_name == " glob" ) {
107110 return HandleGlob (f);
@@ -112,6 +115,9 @@ class SimpleElaborator : public BaseNodeReplacementVisitor {
112115 if (fun_name == " len" ) {
113116 return HandleLen (f);
114117 }
118+ if (fun_name == " range" ) {
119+ return HandleRange (f);
120+ }
115121 if (options_.expand_load_functions && fun_name == " load" ) {
116122 HandleLoad (f);
117123 }
@@ -801,6 +807,39 @@ class SimpleElaborator : public BaseNodeReplacementVisitor {
801807 return fun;
802808 }
803809
810+ static std::optional<int64_t > GetIntAt (List *list, size_t pos) {
811+ if (pos >= list->size ()) return std::nullopt ;
812+ Scalar *const scalar = list->at (pos)->CastAsScalar ();
813+ if (!scalar) return std::nullopt ;
814+ if (scalar->type () != Scalar::ScalarType::kInt ) return std::nullopt ;
815+ return scalar->AsInt ();
816+ }
817+
818+ Node *HandleRange (FunCall *fun) {
819+ if (fun->argument ()->size () < 2 ) return fun;
820+ auto start = GetIntAt (fun->argument (), 0 );
821+ auto end = GetIntAt (fun->argument (), 1 );
822+ auto step = GetIntAt (fun->argument (), 2 );
823+ if (!start || !end) return fun;
824+ if (!step.has_value ()) {
825+ step = 1 ;
826+ }
827+
828+ List *result = Make<List>(List::Type::kList );
829+ if (step.value () == 0 ) {
830+ return result; // next best thing to an infinite range.
831+ }
832+ const int64_t range = *end - *start;
833+ int64_t elements = range / *step;
834+ // We don't co-routine yield that, just creating a concrete list.
835+ const auto &location = project_->GetLocation (fun->identifier ()->id ());
836+ if (elements <= 0 || elements > 20'000 ) return result; // prevent DoS
837+ for (int64_t i = *start; elements > 0 ; i += *step, elements--) {
838+ result->Append (project_->arena (), MakeIntWithStringRep (location, i));
839+ }
840+ return result;
841+ }
842+
804843 // Load potential starlark files and extract requested variables.
805844 void HandleLoad (FunCall *load_fun) {
806845 const auto args = query::ExtractStringList (load_fun->argument ());
0 commit comments