...

Source file src/cuelang.org/go/cue/interpreter/wasm/builtin.go

Documentation: cuelang.org/go/cue/interpreter/wasm

     1  // Copyright 2023 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package wasm
    16  
    17  import (
    18  	"cuelang.org/go/cue"
    19  	"cuelang.org/go/internal/core/adt"
    20  	"cuelang.org/go/internal/pkg"
    21  	"cuelang.org/go/internal/value"
    22  )
    23  
    24  // generateCallThatReturnsBuiltin returns a call expression to a nullary
    25  // builtin that returns another builtin that corresponds to the external
    26  // Wasm function declared by the user. name is the name of the function,
    27  // args are its declared arguments, scope is a CUE value that represents
    28  // the structure into which to resolve the arguments and i is the
    29  // loaded Wasm instance that contains the function.
    30  //
    31  // This function is implemented as a higher-order function to solve a
    32  // bootstrapping issue. The user can specifies arbitrary types for the
    33  // function's arguments, and these types can be arbitrary CUE types
    34  // defined in arbitrary places. This function is called before CUE
    35  // evaluation at a time where identifiers are not yet resolved. This
    36  // higher-order design solves the bootstrapping issue by deferring the
    37  // resolution of identifiers (and selectors, and expressions in general)
    38  // until runtime. At compile-time we only generate a nullary builtin
    39  // that we call, and being nullary, it does not need to refer to any
    40  // unresolved identifiers, rather the identifiers (and selectors) are
    41  // saved in the closure that executes later, at runtime.
    42  //
    43  // Additionally, resolving identifiers (and selectors) requires an
    44  // OpContext, and we do not have an OpContext at compile time. With
    45  // this higher-order design we get an appropiate OpContext when the
    46  // runtime calls the nullary builtin hence solving the bootstrapping
    47  // problem.
    48  func generateCallThatReturnsBuiltin(name string, scope adt.Value, args []string, i *instance) (adt.Expr, error) {
    49  	// ensure that the function exists before trying to call it.
    50  	_, err := i.load(name)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	call := &adt.CallExpr{Fun: &adt.Builtin{
    56  		Result: adt.TopKind,
    57  		Name:   name,
    58  		Func: func(opctx *adt.OpContext, _ []adt.Value) adt.Expr {
    59  			scope := value.Make(opctx, scope)
    60  			sig := compileStringsInScope(args, scope)
    61  			args, result := splitLast(sig)
    62  			b := &pkg.Builtin{
    63  				Name:   name,
    64  				Params: params(args),
    65  				Result: result.Kind(),
    66  				Func:   cABIFunc(i, name, sig),
    67  			}
    68  			return pkg.ToBuiltin(b)
    69  		},
    70  	}}
    71  	return call, nil
    72  }
    73  
    74  // param converts a CUE value that represents the type of a function
    75  // argument into its pkg.Param counterpart.
    76  func param(arg cue.Value) pkg.Param {
    77  	param := pkg.Param{
    78  		Kind: arg.IncompleteKind(),
    79  	}
    80  	if param.Kind == adt.StructKind || ((param.Kind & adt.NumberKind) != 0) {
    81  		_, v := value.ToInternal(arg)
    82  		param.Value = v
    83  	}
    84  	return param
    85  }
    86  
    87  // params converts a list of CUE values that represent the types of a
    88  // function's arguments into their pkg.Param counterparts.
    89  func params(args []cue.Value) []pkg.Param {
    90  	var params []pkg.Param
    91  	for _, a := range args {
    92  		params = append(params, param(a))
    93  	}
    94  	return params
    95  }
    96  

View as plain text