lang: Add a for loop statement for iterating over a list

This adds a for statement which is used to iterate over a list with a
body of statements. This is an important data transformation tool which
should be used sparingly, but is important to have.

An import statement inside of a for loop is not currently supported. We
have a simple hack to detect the obvious cases, but more deeply nested
scenarios probably won't be caught, and you'll get an obscure error
message if you try to do this.

This was incredibly challenging to get right, and it's all thanks to Sam
for his brilliance.

Co-authored-by: Samuel Gélineau <gelisam@gmail.com>
This commit is contained in:
James Shubin
2025-03-04 21:55:29 -05:00
parent c456a5ab97
commit cf7e73bbf6
63 changed files with 2814 additions and 203 deletions

View File

@@ -290,16 +290,23 @@ func (obj *Lang) Init(ctx context.Context) error {
// we assume that for some given code, the list of funcs doesn't change
// iow, we don't support variable, variables or absurd things like that
obj.graph = &pgraph.Graph{Name: "functionGraph"}
env := make(map[string]interfaces.Func)
for k, v := range scope.Variables {
g, builtinFunc, err := v.Graph(nil)
if err != nil {
return errwrap.Wrapf(err, "calling Graph on builtins")
}
obj.graph.AddGraph(g)
env[k] = builtinFunc
}
g, err := obj.ast.Graph() // build the graph of functions
env := interfaces.EmptyEnv()
// XXX: Do we need to do something like this?
//for k, v := range scope.Variables {
// g, builtinFunc, err := v.Graph(nil)
// if err != nil {
// return errwrap.Wrapf(err, "calling Graph on builtins")
// }
// obj.graph.AddGraph(g)
// env.Variables[k] = builtinFunc // XXX: Ask Sam (.Functions ???)
//}
//for k, v := range scope.Functions {
// env.Functions[k] = &interfaces.Closure{
// Env: interfaces.EmptyEnv(),
// Expr: v,
// }
//}
g, err := obj.ast.Graph(env) // build the graph of functions
if err != nil {
return errwrap.Wrapf(err, "could not generate function graph")
}