// Scalar built-in application helpers: positional argument access, the// range/substring/toString value builders, and the datetime/duration// constructors with their checked integer arithmetic. Split from funcs.go,// which holds the function registry (ResolveFuncOp) and the ApplyFunc// dispatch.
package evalimport ()// arg reads argv[i], Null when absent.func arg( []value.Value, int) value.Value {if < len() {return [] }returnvalue.Null()}// numArg is the single numeric argument of a math function as float64// (Int or Float), comma-ok.func numArg( []value.Value) (float64, bool) {returnarg(, 0).AsFloat()}// applyRange is range(start, end[, step]): the inclusive integer sequence// (step defaults to 1; a zero step is null).func applyRange( []value.Value) value.Value { , := arg(, 0).AsInt() , := arg(, 1).AsInt()if ! || ! {returnvalue.Null() } := int64(1)iflen() >= 3 {if , := arg(, 2).AsInt(); { = } }if == 0 {returnvalue.Null() }var []value.Valuefor := ; ( > 0 && <= ) || ( < 0 && >= ); += { = append(, value.Int()) }returnvalue.List()}// asciiOnly reports whether s holds only single-byte runes, so character// indexing equals byte indexing.func asciiOnly( string) bool {for := 0; < len(); ++ {if [] >= 0x80 {returnfalse } }returntrue}// applySubstring is substring(s, start[, len]): character-based, start// past the end yields ""; a null string or negative start/len is null.// An all-ASCII source -- the overwhelmingly common case -- slices the// input string directly (a Go substring shares the backing), skipping the// rune conversion and the fresh string a hot aggregate argument would// otherwise pay per row.func applySubstring( []value.Value) value.Value { , := arg(, 0).AsStr() , := arg(, 1).AsInt()if ! || ! || < 0 {returnvalue.Null() }ifasciiOnly() { := min(int(), len())iflen() >= 3 { , := arg(, 2).AsInt()if ! || < 0 {returnvalue.Null() } := min(+int(), len())returnvalue.Str([:]) }returnvalue.Str([:]) } := []rune() := min(int(), len())iflen() >= 3 { , := arg(, 2).AsInt()if ! || < 0 {returnvalue.Null() } := min(+int(), len())returnvalue.Str(string([:])) }returnvalue.Str(string([:]))}// applyToString renders a scalar as a string: an integral Float keeps a// trailing .0 (openCypher prints 1.0, not 1); inf/NaN render as the Rust// engine prints them so cross-engine goldens agree.func applyToString( value.Value) value.Value {switch .Kind() {casevalue.KindInt: , := .AsInt()returnvalue.Str(strconv.FormatInt(, 10))casevalue.KindFloat: , := .AsFloat()switch {casemath.IsNaN():returnvalue.Str("NaN")casemath.IsInf(, 1):returnvalue.Str("inf")casemath.IsInf(, -1):returnvalue.Str("-inf")case == math.Trunc():returnvalue.Str(strconv.FormatFloat(, 'f', 1, 64)) }returnvalue.Str(strconv.FormatFloat(, 'f', -1, 64))casevalue.KindBool: , := .AsBool()returnvalue.Str(strconv.FormatBool())casevalue.KindStr:returncasevalue.KindTemporal: , , := .AsTemporal()returnvalue.Str(ISOString(, )) }// A duration has no single established string form here (the wasm/Python // surfaces emit the {months, days, millis} component form, not a string), // so toString(duration) stays Null rather than bake an arbitrary choice.returnvalue.Null()}// buildDatetime builds a temporal from a datetime(...) argument: an ISO// string, an i64 epoch-millis, another temporal (kind changes), an// {epochMillis: n} map, or a {year, month, day, hour, ...} component map.func buildDatetime( value.Value, value.TemporalKind) value.Value {switch .Kind() {casevalue.KindStr: , := .AsStr()if , := ParseISO(); {returnvalue.Temporal(, ) }casevalue.KindInt: , := .AsInt()returnvalue.Temporal(, )casevalue.KindTemporal: , , := .AsTemporal()returnvalue.Temporal(, )casevalue.KindMap: , := .AsMap() := func( string) (int64, bool) { returnmapGet(, ).AsInt() }if , := ("epochMillis"); {returnvalue.Temporal(, ) }if , := ("year"); { := func( string, int64) int64 {if , := (); {return }return } , := sumScaled( [2]int64{("hour", 0), 3_600_000}, [2]int64{("minute", 0), 60_000}, [2]int64{("second", 0), 1000}, [2]int64{("millisecond", 0), 1})if ! {returnvalue.Null() } , := civilMillis(, uint32(("month", 1)), uint32(("day", 1)), )if ! {returnvalue.Null() }returnvalue.Temporal(, ) } }returnvalue.Null()}// buildDuration builds a duration from a duration({years, months, weeks,// days, hours, minutes, seconds, milliseconds}) map.func buildDuration( []value.MapEntry) value.Value { := func( string) int64 {if , := mapGet(, ).AsInt(); {return }return0 }// Unit conversions overflow at build time, before any temporal is // touched; a wrapped duration would silently corrupt every later add. , := addMul(("years"), 12, ("months")) , := addMul(("weeks"), 7, ("days")) , := sumScaled( [2]int64{("hours"), 3_600_000}, [2]int64{("minutes"), 60_000}, [2]int64{("seconds"), 1000}, [2]int64{("milliseconds"), 1})if ! || ! || ! {returnvalue.Null() }returnvalue.Duration(, , )}// addMul is checked a*k + b, comma-ok.func addMul(, , int64) (int64, bool) { , := mulChk(, )if ! {return0, false }returnaddChk(, )}// sumScaled is the checked sum of value*scale terms, comma-ok.func sumScaled( ...[2]int64) (int64, bool) {varint64for , := range { , := mulChk([0], [1])if ! {return0, false }if , = addChk(, ); ! {return0, false } }return , true}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.