scripts

package
v0.0.0-...-20810c9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 21, 2024 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ASSERT_ERROR = errors.New("Assertion error")
View Source
var BREAK = errors.New("Break")
View Source
var ERROR = errors.New("Error")
View Source
var ErrorEndExpected = errors.New("End of element not found")
View Source
var ErrorEndUnexpected = errors.New("End of element")
View Source
var ErrorWrongElement = errors.New("Wrong element")
View Source
var FUNCTION_NOT_FOUND = errors.New("Function not found")
View Source
var INDEX_OUTSIDE_ARRAY = errors.New("Index outside of array")
View Source
var INVALID_BINARY = errors.New("Invalid binary operation for types")
View Source
var INVALID_BINARY_TYPE = errors.New("Invalid type for binary operation")
View Source
var INVALID_BOOL_TYPE = errors.New("Value could not be converted to bool")
View Source
var INVALID_COMPARE_TYPE = errors.New("Types incomparable")
View Source
var INVALID_COMPARISON = errors.New("Invalid comparison for types")
View Source
var INVALID_REF = errors.New("Undefined reference")
View Source
var INVALID_UNARY = errors.New("Invalid unary operation for type")
View Source
var InspectCompilerEntries []CompilerEntry[InspectExpr] = []CompilerEntry[InspectExpr]{

	CreateEntry(func(e And, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesBool
			},
		}
	}),

	CreateEntry(func(e Or, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesBool
			},
		}
	}),

	CreateEntry(func(e Not, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesBool
			},
		}
	}),

	CreateEntry(func(e Body, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesVoid
			},
		}
	}),

	CreateEntry(func(e If, c *Compiler[InspectExpr]) InspectExpr {
		compiled, err := IfCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				ret := Types{}
				for _, cond := range compiled.Cases {
					ret.AddTypes(cond.Then.ReturnType(state))
				}
				if compiled.Else.ReturnType == nil {
					ret.AddTypes(typesVoid)
				} else {
					ret.AddTypes(compiled.Else.ReturnType(state))
				}
				return ret
			},
		}
	}),

	CreateEntry(func(e Switch, c *Compiler[InspectExpr]) InspectExpr {
		compiled, err := SwitchCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				ret := Types{}
				for _, cond := range compiled.Cases {
					ret.AddTypes(cond.Then.ReturnType(state))
				}
				if compiled.Default.ReturnType == nil {
					ret.AddTypes(typesVoid)
				} else {
					ret.AddTypes(compiled.Default.ReturnType(state))
				}
				return ret
			},
		}
	}),

	CreateEntry(func(e Loop, c *Compiler[InspectExpr]) InspectExpr {
		compiled, err := LoopCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				if compiled.Then.ReturnType == nil {
					return typesVoid
				}
				ret := Types{}
				ret.AddTypes(compiled.Then.ReturnType(state))
				ret.AddTypes(typesVoid)
				return ret
			},
		}
	}),

	CreateEntry(func(e Break, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return nil
			},
		}
	}),

	CreateEntry(func(e Return, c *Compiler[InspectExpr]) InspectExpr {
		compiled, err := ReturnCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				if compiled.Value.ReturnType == nil {
					return typesVoid
				}
				return compiled.Value.ReturnType(state)
			},
		}
	}),

	CreateEntry(func(e Throw, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return nil
			},
		}
	}),

	CreateEntry(func(e Try, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return nil
			},
		}
	}),

	CreateEntry(func(e Assert, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return nil
			},
		}
	}),

	CreateEntry(func(e Constant, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return Types{reflect.TypeOf(e.Value): struct{}{}}
			},
		}
	}),

	CreateEntry(func(e Compare, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesBool
			},
		}
	}),

	CreateEntry(func(e Binary, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesNumber
			},
		}
	}),

	CreateEntry(func(e Unary, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesNumber
			},
		}
	}),

	CreateEntry(func(e Get, c *Compiler[InspectExpr]) InspectExpr {

		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {

				return typesAny
			},
		}
	}),

	CreateEntry(func(e Set, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesVoid
			},
		}
	}),

	CreateEntry(func(e Invoke, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				f, fExists := state.Runtime.Funcs[e.Function]
				if !fExists {
					return nil
				}
				return Types{f.ReturnType: struct{}{}}
			},
		}
	}),

	CreateEntry(func(e Define, c *Compiler[InspectExpr]) InspectExpr {
		compiled, err := DefineCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return compiled.Body.ReturnType(state)
			},
		}
	}),

	CreateEntry(func(e Template, c *Compiler[InspectExpr]) InspectExpr {
		return InspectExpr{
			expr: e,
			ReturnType: func(state *State) Types {
				return typesString
			},
		}
	}),
}

The collection of standard InspectExpr compiler entries.

View Source
var MAX_ITERATIONS = errors.New("Max iterations met")
View Source
var RETURN = errors.New("Return")
View Source
var RunCompilerEntries []CompilerEntry[RunExpr] = []CompilerEntry[RunExpr]{

	CreateEntry(func(e And, c *Compiler[RunExpr]) RunExpr {
		if e.Conditions == nil || len(e.Conditions) == 0 {
			return c.CreateError(e, errors.New("And must have at least one condition."))
		}
		compiled, err := AndCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				for _, cond := range compiled.Conditions {
					result, err := runBool(cond, state)
					if err != nil {
						return false, ExprError{e, err}
					}
					if !result {
						return false, nil
					}
				}
				return true, nil
			},
		}
	}),

	CreateEntry(func(e Or, c *Compiler[RunExpr]) RunExpr {
		if e.Conditions == nil || len(e.Conditions) == 0 {
			return c.CreateError(e, errors.New("Or must have at least one condition."))
		}
		compiled, err := OrCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				for _, cond := range compiled.Conditions {
					result, err := runBool(cond, state)
					if err != nil {
						return false, ExprError{e, err}
					}
					if result {
						return true, nil
					}
				}
				return false, nil
			},
		}
	}),

	CreateEntry(func(e Not, c *Compiler[RunExpr]) RunExpr {
		compiled, err := NotCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				result, err := runBool(compiled.Condition, state)
				if err != nil {
					return false, ExprError{e, err}
				}
				return !result, nil
			},
		}
	}),

	CreateEntry(func(e Body, c *Compiler[RunExpr]) RunExpr {
		compiled, err := BodyCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				for _, item := range compiled.Lines {
					result, err := item.Run(state)
					if err != nil {
						return result, ExprError{e, err}
					}
				}
				return nil, nil
			},
		}
	}),

	CreateEntry(func(e If, c *Compiler[RunExpr]) RunExpr {
		if e.Cases == nil || len(e.Cases) == 0 {
			return c.CreateError(e, errors.New("If must have at least one if then statement."))
		}
		compiled, err := IfCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				for _, ifCase := range compiled.Cases {
					result, err := runBool(ifCase.Condition, state)
					if err != nil {
						return nil, nil
					}
					if result {
						thenResult, err := ifCase.Then.Run(state)
						if err != nil {
							return nil, ExprError{e, err}
						}
						return thenResult, nil
					}
				}
				if compiled.Else.Run != nil {
					result, err := compiled.Else.Run(state)
					if err != nil {
						return nil, ExprError{e, err}
					}
					return result, nil
				}
				return nil, nil
			},
		}
	}),

	CreateEntry(func(e Switch, c *Compiler[RunExpr]) RunExpr {
		if e.Cases == nil || len(e.Cases) == 0 {
			return c.CreateError(e, errors.New("Switch must have at least one case statement."))
		}
		compiled, err := SwitchCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				value, err := compiled.Value.Run(state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				for _, switchCase := range compiled.Cases {
					for _, switchExpected := range switchCase.Expected {
						expected, err := switchExpected.Run(state)
						if err != nil {
							return nil, ExprError{e, err}
						}
						if expected == value {
							result, err := switchCase.Then.Run(state)
							if err != nil {
								return nil, ExprError{e, err}
							}
							return result, nil
						}
					}
				}
				if compiled.Default.Run != nil {
					result, err := compiled.Default.Run(state)
					if err != nil {
						return nil, ExprError{e, err}
					}
					return result, nil
				}
				return nil, nil
			},
		}
	}),

	CreateEntry(func(e Loop, c *Compiler[RunExpr]) RunExpr {
		compiled, err := LoopCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				state.EnterScope()
				defer state.ExitScope()
				if compiled.Start.Run != nil {
					_, err := compiled.Start.Run(state)
					if err != nil {
						return nil, ExprError{e, err}
					}
				}
				iterations := 0
				for {
					if compiled.While.Run != nil {
						result, err := runBool(compiled.While, state)
						if err != nil {
							return nil, ExprError{e, err}
						}
						if !result {
							break
						}
					}
					if compiled.Then.Run != nil {
						result, err := compiled.Then.Run(state)
						if hasRootCause(err, BREAK) {
							break
						} else if err != nil {
							return result, ExprError{e, err}
						}
					}
					if compiled.Next.Run != nil {
						_, err := compiled.Next.Run(state)
						if err != nil {
							return nil, ExprError{e, err}
						}
					}
					iterations++
					if state.Runtime.MaxIterations != 0 && iterations >= state.Runtime.MaxIterations {
						return nil, MAX_ITERATIONS
					}
				}
				return nil, nil
			},
		}
	}),

	CreateEntry(func(e Break, c *Compiler[RunExpr]) RunExpr {
		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				return nil, BREAK
			},
		}
	}),

	CreateEntry(func(e Return, c *Compiler[RunExpr]) RunExpr {
		compiled, err := ReturnCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				if compiled.Value.Run == nil {
					return nil, RETURN
				}
				result, err := compiled.Value.Run(state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				return result, RETURN
			},
		}
	}),

	CreateEntry(func(e Throw, c *Compiler[RunExpr]) RunExpr {
		compiled, err := ThrowCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				if compiled.Error.Run == nil {
					return nil, ERROR
				}
				result, err := runString(compiled.Error, state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				return result, ExprError{e, errors.New(result)}
			},
		}
	}),

	CreateEntry(func(e Try, c *Compiler[RunExpr]) RunExpr {
		compiled, err := TryCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				result, err := compiled.Body.Run(state)
				if err != nil {
					if hasRootCause(err, BREAK) || hasRootCause(err, RETURN) {
						return result, err
					}
					if compiled.Catch.Run != nil {
						inner := state.EnterScope()
						inner.Ref("error").Set(err.Error())
						result, err = compiled.Catch.Run(state)
						state.ExitScope()
					}
				}
				if compiled.Finally.Run != nil {
					finallyResult, finallyErr := compiled.Finally.Run(state)
					if hasRootCause(finallyErr, BREAK) || hasRootCause(finallyErr, RETURN) {
						result = finallyResult
					} else if err == nil {
						err = finallyErr
					}
				}
				return result, err
			},
		}
	}),

	CreateEntry(func(e Assert, c *Compiler[RunExpr]) RunExpr {
		compiled, err := AssertCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				result, err := runBool(compiled.Expect, state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				if result {
					return nil, nil
				}
				assertion := ExprError{e, ASSERT_ERROR}
				if compiled.Error.Run != nil {
					message, err := runString(compiled.Error, state)
					if err != nil {
						return nil, ExprError{e, err}
					}
					assertion.inner = errors.New(message)
				}
				return nil, state.Assert(assertion)
			},
		}
	}),

	CreateEntry(func(e Constant, c *Compiler[RunExpr]) RunExpr {
		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				return e.Value, nil
			},
		}
	}),

	CreateEntry(func(e Compare, c *Compiler[RunExpr]) RunExpr {
		compiled, err := CompareCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				leftRaw, err := compiled.Left.Run(state)
				if err != nil {
					return false, ExprError{e, err}
				}
				rightRaw, err := compiled.Right.Run(state)
				if err != nil {
					return false, ExprError{e, err}
				}

				leftBase := concrete(leftRaw)
				rightBase := concrete(rightRaw)

				if !leftBase.IsValid() {
					return false, ExprError{e, fmt.Errorf("Invalid left value in compare")}
				}
				if !rightBase.IsValid() {
					return false, ExprError{e, fmt.Errorf("Invalid right value in compare")}
				}

				leftRaw = leftBase.Interface()
				rightRaw = rightBase.Interface()

				if leftString, ok := leftRaw.(string); ok {
					if rightString, ok := rightRaw.(string); ok {
						if state.Runtime.Insensitive {
							leftString = strings.ToLower(leftString)
							rightString = strings.ToLower(rightString)
						}
						switch e.Type {
						case EQ:
							return leftString == rightString, nil
						case NEQ:
							return leftString != rightString, nil
						case LT:
							return leftString < rightString, nil
						case GT:
							return leftString > rightString, nil
						case LTE:
							return leftString <= rightString, nil
						case GTE:
							return leftString >= rightString, nil
						default:
							return false, INVALID_COMPARISON
						}
					}
				}

				if leftBool, ok := leftRaw.(bool); ok {
					if rightBool, ok := rightRaw.(bool); ok {
						switch e.Type {
						case EQ:
							return leftBool == rightBool, nil
						case NEQ:
							return leftBool != rightBool, nil
						default:
							return false, INVALID_COMPARISON
						}
					}
				}

				left, leftErr := toFloat(leftRaw)
				right, rightErr := toFloat(rightRaw)

				if leftErr == nil && rightErr == nil {
					switch e.Type {
					case EQ:
						return math.Abs(left-right) <= state.Runtime.Epsilon, nil
					case NEQ:
						return math.Abs(left-right) > state.Runtime.Epsilon, nil
					case LT:
						return left < right, nil
					case LTE:
						return left <= right, nil
					case GT:
						return left > right, nil
					case GTE:
						return left >= right, nil
					}
				}

				switch e.Type {
				case EQ:
					return leftRaw == rightRaw, nil
				case NEQ:
					return leftRaw != rightRaw, nil
				}

				return false, INVALID_COMPARISON
			},
		}
	}),

	CreateEntry(func(e Binary, c *Compiler[RunExpr]) RunExpr {
		compiled, err := BinaryCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				leftRaw, err := compiled.Left.Run(state)
				if err != nil {
					return false, ExprError{e, err}
				}
				rightRaw, err := compiled.Right.Run(state)
				if err != nil {
					return false, ExprError{e, err}
				}

				leftBase := concrete(leftRaw)
				rightBase := concrete(rightRaw)

				if !leftBase.IsValid() {
					return false, ExprError{e, fmt.Errorf("Invalid left value in binary operation")}
				}
				if !rightBase.IsValid() {
					return false, ExprError{e, fmt.Errorf("Invalid right value in binary operation")}
				}

				leftRaw = leftBase.Interface()
				rightRaw = rightBase.Interface()

				if leftString, ok := leftRaw.(string); ok {
					if rightString, ok := rightRaw.(string); ok {

						switch e.Type {
						case ADD:
							return leftString + rightString, nil
						default:
							return false, INVALID_BINARY
						}
					}
				}

				if leftBool, ok := leftRaw.(bool); ok {
					if rightBool, ok := rightRaw.(bool); ok {
						switch e.Type {
						case AND:
							return leftBool && rightBool, nil
						case OR:
							return leftBool || rightBool, nil
						case XOR:
							return leftBool != rightBool, nil
						default:
							return false, INVALID_BINARY
						}
					}
				}

				switch e.Type {
				case AND, OR, XOR, LSHIFT, RSHIFT, GCD:
					left, leftErr := toInt(leftRaw)
					if leftErr != nil {
						return false, leftErr
					}
					right, rightErr := toInt(rightRaw)
					if rightErr != nil {
						return false, rightErr
					}
					switch e.Type {
					case AND:
						return left & right, nil
					case OR:
						return left | right, nil
					case XOR:
						return left ^ right, nil
					case LSHIFT:
						return left << right, nil
					case RSHIFT:
						return left >> right, nil
					case GCD:
						for right != 0 {
							t := right
							right = left % right
							left = t
						}
						return left, nil
					}
				case ADD, SUB, MUL, DIV, MOD, POW, MAX, MIN, ATAN2:
					left, leftErr := toFloat(leftRaw)
					if leftErr != nil {
						return false, leftErr
					}
					right, rightErr := toFloat(rightRaw)
					if rightErr != nil {
						return false, rightErr
					}
					switch e.Type {
					case ADD:
						return left + right, nil
					case SUB:
						return left - right, nil
					case MUL:
						return left * right, nil
					case DIV:
						return left / right, nil
					case MOD:
						return math.Mod(left, right), nil
					case POW:
						return math.Pow(left, right), nil
					case MAX:
						return math.Max(left, right), nil
					case MIN:
						return math.Min(left, right), nil
					case ATAN2:
						return math.Atan2(left, right), nil
					}
				}

				return false, INVALID_BINARY
			},
		}
	}),

	CreateEntry(func(e Unary, c *Compiler[RunExpr]) RunExpr {
		compiled, err := UnaryCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				valueRaw, err := compiled.Value.Run(state)
				if err != nil {
					return false, ExprError{e, err}
				}

				valueBase := concrete(valueRaw)

				if !valueBase.IsValid() {
					return false, ExprError{e, fmt.Errorf("Invalid value in unary operation")}
				}

				valueRaw = valueBase.Interface()

				valueFloat, err := toFloat(valueRaw)
				if err != nil {
					return 0, err
				}

				switch e.Type {
				case NEG:
					return -valueFloat, nil
				case NOT:
					return ^int64(valueFloat), nil
				case SQR:
					return valueFloat * valueFloat, nil
				case ABS:
					return math.Abs(valueFloat), nil
				case COS:
					return math.Cos(valueFloat), nil
				case SIN:
					return math.Sin(valueFloat), nil
				case TAN:
					return math.Tan(valueFloat), nil
				case ACOS:
					return math.Acos(valueFloat), nil
				case ASIN:
					return math.Asin(valueFloat), nil
				case ATAN:
					return math.Atan(valueFloat), nil
				case FLOOR:
					return math.Floor(valueFloat), nil
				case CEIL:
					return math.Ceil(valueFloat), nil
				case ROUND:
					return math.Round(valueFloat), nil
				case SQRT:
					return math.Sqrt(valueFloat), nil
				case CBRT:
					return math.Cbrt(valueFloat), nil
				case LN:
					return math.Log(valueFloat), nil
				case LOG2:
					return math.Log2(valueFloat), nil
				case LOG10:
					return math.Log10(valueFloat), nil
				case TRUNC:
					return math.Trunc(valueFloat), nil
				}

				return 0, INVALID_UNARY
			},
		}
	}),

	CreateEntry(func(e Get, c *Compiler[RunExpr]) RunExpr {
		compiled, err := GetCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				ref, err := pathRef(compiled.Path, state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				if refError := ref.GetError(); refError != nil {
					return nil, refError
				}
				return ref.Value.Interface(), nil
			},
		}
	}),

	CreateEntry(func(e Set, c *Compiler[RunExpr]) RunExpr {
		compiled, err := SetCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				ref, err := pathRef(compiled.Path, state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				if refError := ref.GetError(); refError != nil {
					return nil, refError
				}
				value, err := compiled.Value.Run(state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				err = ref.Set(value)
				if err != nil {
					return nil, ExprError{e, err}
				}
				return nil, nil
			},
		}
	}),

	CreateEntry(func(e Invoke, c *Compiler[RunExpr]) RunExpr {
		if e.Function == "" {
			return c.CreateError(e, errors.New("Function not specified"))
		}
		compiled, err := InvokeCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				f, fExists := state.Runtime.Funcs[compiled.Function]
				if !fExists {
					return nil, FUNCTION_NOT_FOUND
				}
				params := make([]reflect.Value, 0)
				for _, arg := range f.Arguments {
					paramValue := valueOf(arg.Type)
					if paramExpr, ok := compiled.Params[arg.Name]; ok {
						param, err := paramExpr.Run(state)
						if err != nil {
							return nil, ExprError{e, err}
						}
						paramValue = toType(param, arg.Type)
						if !paramValue.IsValid() {
							return nil, ExprError{e, fmt.Errorf("Invalid argument %s for %s", arg.Name, e.Function)}
						}
					}
					params = append(params, paramValue)
				}
				results := f.Implementation.Call(params)
				result := any(nil)
				err := error(nil)
				if len(results) > 0 {
					first := results[0]
					if firstError, ok := first.Interface().(error); ok {
						err = firstError
					} else {
						result = first.Interface()
						if len(results) > 1 {
							second := results[0]
							if secondError, ok := second.Interface().(error); ok {
								err = secondError
							}
						}
					}
				}
				if err != nil {
					return result, ExprError{e, err}
				}
				return result, nil
			},
		}
	}),

	CreateEntry(func(e Define, c *Compiler[RunExpr]) RunExpr {
		if e.Vars == nil || len(e.Vars) == 0 {
			return c.CreateError(e, errors.New("Define requires at least one variable definition."))
		}
		compiled, err := DefineCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				scope := state.EnterScope()
				defer state.ExitScope()
				for _, varPair := range compiled.Vars {
					varRef := scope.Ref(varPair.Name)
					if !varRef.Valid() {
						return nil, varRef.Error
					}
					varValue, err := varPair.Value.Run(state)
					if err != nil {
						return nil, ExprError{e, err}
					}
					err = varRef.Set(varValue)
					if err != nil {
						return nil, ExprError{e, err}
					}
				}
				result, err := compiled.Body.Run(state)
				if err != nil {
					return nil, ExprError{e, err}
				}
				return result, nil
			},
		}
	}),

	CreateEntry(func(e Template, c *Compiler[RunExpr]) RunExpr {
		compiled, err := TemplateCompile(c, e)
		if err != nil {
			return c.CreateError(e, err)
		}

		return RunExpr{
			expr: e,
			Run: func(state *State) (any, error) {
				format, err := runString(compiled.Format, state)
				if err != nil {
					return "", ExprError{e, err}
				}
				formatParsed, err := template.New(format).Parse(format)
				if err != nil {
					return "", ExprError{e, err}
				}
				vars := make(map[string]any)
				for varName, varExpr := range compiled.Vars {
					varValue, err := varExpr.Run(state)
					if err != nil {
						return "", ExprError{e, err}
					}
					vars[varName] = concrete(varValue).Interface()
				}
				out := bytes.Buffer{}
				err = formatParsed.Execute(&out, vars)
				if err != nil {
					return "", ExprError{e, err}
				}
				return out.String(), nil
			},
		}
	}),
}

The collection of standard RunExpr compiler entries.

View Source
var XmlEntries []XmlEntry = []XmlEntry{

	NewXmlEntry(
		func(e xmlElement, x *Xml) (And, error) {
			conditions, err := x.DecodeRangedList(e.children, 1, -1)
			return And{Conditions: conditions}, err
		},
		func(in And, e *xmlElement, x *Xml) error {
			conditions, err := x.EncodeList(in.Conditions)
			if err != nil {
				return err
			}
			e.append(conditions)
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Or, error) {
			conditions, err := x.DecodeRangedList(e.children, 1, -1)
			return Or{Conditions: conditions}, err
		},
		func(in Or, e *xmlElement, x *Xml) error {
			conditions, err := x.EncodeList(in.Conditions)
			if err != nil {
				return err
			}
			e.append(conditions)
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Not, error) {
			els := e.children.getElements()
			if len(els) != 1 {
				return Not{}, errors.New("Not can only have one expression")
			}
			condition, err := x.Decode(els[0])
			return Not{Condition: condition}, err
		},
		func(in Not, e *xmlElement, x *Xml) error {
			condition, err := x.Encode(in.Condition)
			if err != nil {
				return err
			}
			e.addElement(condition)
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Body, error) {
			lines, err := x.DecodeList(e.children)
			return Body{Lines: lines}, err
		},
		func(in Body, e *xmlElement, x *Xml) error {
			lines, err := x.EncodeList(in.Lines)
			if err != nil {
				return err
			}
			e.append(lines)
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (If, error) {
			out := If{[]IfCase{}, nil}

			err := e.children.sequential([]nodeSequence{
				{
					name: "case",
					min:  1,
					handle: handleList(x, 2, func(inner []Expr) error {
						out.Cases = append(out.Cases, IfCase{
							Condition: inner[0],
							Then:      inner[1],
						})
						return nil
					}),
				},
				{
					name: "else",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Else = inner[0]
						return nil
					}),
				},
			})

			return out, err
		},
		func(in If, e *xmlElement, x *Xml) error {
			for _, ifCase := range in.Cases {
				condition, err := x.Encode(ifCase.Condition)
				if err != nil {
					return nil
				}
				then, err := x.Encode(ifCase.Then)
				if err != nil {
					return err
				}
				e.addNamedElement("case", xmlNodes{
					condition.toAny(),
					then.toAny(),
				})
			}
			if in.Else != nil {
				els, err := x.Encode(in.Else)
				if err != nil {
					return err
				}
				e.addNamedElement("else", els.toNodes())
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Switch, error) {
			out := Switch{nil, []SwitchCase{}, nil}

			err := e.children.sequential([]nodeSequence{
				{
					name: "value",
					min:  1,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Value = inner[0]
						return nil
					}),
				},
				{
					name: "case",
					min:  1,
					handle: func(c xmlElement, comments []xmlNode[xml.Comment]) error {
						switchCase := SwitchCase{}

						err := c.children.sequential([]nodeSequence{
							{
								name: "expected",
								min:  1,
								max:  1,
								handle: func(c xmlElement, comments []xmlNode[xml.Comment]) error {
									inner, err := x.DecodeRangedList(c.children, 1, -1)
									if err != nil {
										return err
									}
									switchCase.Expected = inner
									return nil
								},
							},
							{
								name: "then",
								min:  1,
								max:  1,
								handle: handleList(x, 1, func(inner []Expr) error {
									switchCase.Then = inner[0]
									return nil
								}),
							},
						})

						out.Cases = append(out.Cases, switchCase)
						return err
					},
				},
				{
					name: "default",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Default = inner[0]
						return nil
					}),
				},
			})

			return out, err
		},
		func(in Switch, e *xmlElement, x *Xml) error {
			value, err := x.Encode(in.Value)
			if err != nil {
				return err
			}
			e.addNamedElement("value", value.toNodes())
			for _, switchCase := range in.Cases {
				then, err := x.Encode(switchCase.Then)
				if err != nil {
					return err
				}

				expected, err := x.EncodeList(switchCase.Expected)
				if err != nil {
					return err
				}

				e.addNamedElement("case", xmlNodes{
					newXmlElement("expected", expected).toAny(),
					newXmlElement("then", then.toNodes()).toAny(),
				})
			}
			if in.Default != nil {
				elDefault, err := x.Encode(in.Default)
				if err != nil {
					return err
				}
				e.addNamedElement("default", xmlNodes{elDefault.toAny()})
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Loop, error) {
			out := Loop{}

			err := e.children.sequential([]nodeSequence{
				{
					name: "start",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Start = inner[0]
						return nil
					}),
				},
				{
					name: "while",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.While = inner[0]
						return nil
					}),
				},
				{
					name: "then",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Then = inner[0]
						return nil
					}),
				},
				{
					name: "next",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Next = inner[0]
						return nil
					}),
				},
			})

			return out, err
		},
		func(in Loop, e *xmlElement, x *Xml) error {
			if in.Start != nil {
				start, err := x.Encode(in.Start)
				if err != nil {
					return err
				}
				e.addNamedElement("start", xmlNodes{start.toAny()})
			}
			if in.While != nil {
				while, err := x.Encode(in.While)
				if err != nil {
					return err
				}
				e.addNamedElement("while", while.toNodes())
			}
			if in.Then != nil {
				then, err := x.Encode(in.Then)
				if err != nil {
					return err
				}
				e.addNamedElement("then", then.toNodes())
			}
			if in.Next != nil {
				next, err := x.Encode(in.Next)
				if err != nil {
					return err
				}
				e.addNamedElement("next", next.toNodes())
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Break, error) {
			out := Break{}

			_, err := x.DecodeRangedList(e.children, 0, 0)
			if err != nil {
				return out, err
			}

			return out, nil
		},
		func(in Break, e *xmlElement, x *Xml) error {
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Return, error) {
			out := Return{}

			inner, err := x.DecodeRangedList(e.children, 0, 1)
			if err != nil {
				return out, err
			}
			if len(inner) == 1 {
				out.Value = inner[0]
			}

			return out, nil
		},
		func(in Return, e *xmlElement, x *Xml) error {
			if in.Value != nil {
				value, err := x.Encode(in.Value)
				if err != nil {
					return err
				}
				e.addElement(value)
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Throw, error) {
			out := Throw{}

			inner, err := x.DecodeRangedList(e.children, 0, 1)
			if err != nil {
				return out, err
			}
			if len(inner) == 1 {
				out.Error = inner[0]
			}

			return out, nil
		},
		func(in Throw, e *xmlElement, x *Xml) error {
			if in.Error != nil {
				er, err := x.Encode(in.Error)
				if err != nil {
					return err
				}
				e.addElement(er)
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Try, error) {
			out := Try{}

			err := e.children.sequential([]nodeSequence{
				{
					name: "body",
					min:  1,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Body = inner[0]
						return nil
					}),
				},
				{
					name: "catch",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Catch = inner[0]
						return nil
					}),
				},
				{
					name: "finally",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Finally = inner[0]
						return nil
					}),
				},
			})

			return out, err
		},
		func(in Try, e *xmlElement, x *Xml) error {
			body, err := x.Encode(in.Body)
			if err != nil {
				return err
			}
			e.addNamedElement("body", body.toNodes())
			if in.Catch != nil {
				catch, err := x.Encode(in.Catch)
				if err != nil {
					return err
				}
				e.addNamedElement("catch", catch.toNodes())
			}
			if in.Finally != nil {
				finally, err := x.Encode(in.Finally)
				if err != nil {
					return err
				}
				e.addNamedElement("finally", finally.toNodes())
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Assert, error) {
			out := Assert{}

			err := e.children.sequential([]nodeSequence{
				{
					name: "expect",
					min:  1,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Expect = inner[0]
						return nil
					}),
				},
				{
					name: "error",
					min:  0,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Error = inner[0]
						return nil
					}),
				},
			})

			return out, err
		},
		func(in Assert, e *xmlElement, x *Xml) error {
			expect, err := x.Encode(in.Expect)
			if err != nil {
				return err
			}
			e.addNamedElement("expect", expect.toNodes())
			if in.Error != nil {
				er, err := x.Encode(in.Error)
				if err != nil {
					return err
				}
				e.addNamedElement("error", er.toNodes())
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Constant, error) {
			out := Constant{}

			typeName := e.attr("type")
			if typeName == "" {
				return out, fmt.Errorf("Constant type not given.")
			}
			typeKind, exists := x.Types[typeName]
			if !exists {
				return out, fmt.Errorf("Type not defined in XML: %s", typeName)
			}

			textValue := ""
			for _, n := range e.children {
				if textNode, ok := n.token.(xml.CharData); ok {
					textValue += string(textNode)
				}
			}

			value, err := fromString(strings.TrimSpace(textValue), typeKind)
			if err != nil {
				return out, err
			}

			out.Value = value.Interface()

			return out, nil
		},
		func(in Constant, e *xmlElement, x *Xml) error {
			valueType := reflect.TypeOf(in.Value)
			for typeName, typeKind := range x.Types {
				if valueType == typeKind {
					e.token.Attr = []xml.Attr{{
						Name:  xml.Name{Local: "type"},
						Value: typeName,
					}}
					break
				}
			}
			if e.token.Attr == nil || len(e.token.Attr) == 0 {
				return fmt.Errorf("Error saving constant, unregistered type: %v", valueType)
			}

			value, err := toString(in.Value)
			if err != nil {
				return err
			}

			e.children = append(e.children, &xmlNode[any]{
				token: xml.CharData(value),
			})
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Compare, error) {
			out := Compare{}

			opName := e.attr("op")
			if opName == "" {
				return out, fmt.Errorf("Compare op not given.")
			}
			out.Type = CompareOp(opName)

			inner, err := x.DecodeRangedList(e.children, 2, 2)
			if err != nil {
				return out, err
			}

			out.Left = inner[0]
			out.Right = inner[1]

			return out, nil
		},
		func(in Compare, e *xmlElement, x *Xml) error {
			e.token.Attr = []xml.Attr{{
				Name: xml.Name{
					Local: "op",
				},
				Value: string(in.Type),
			}}
			left, err := x.Encode(in.Left)
			if err != nil {
				return err
			}
			e.addElement(left)
			right, err := x.Encode(in.Right)
			if err != nil {
				return err
			}
			e.addElement(right)
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Binary, error) {
			out := Binary{}

			opName := e.attr("op")
			if opName == "" {
				return out, fmt.Errorf("Binary op not given.")
			}
			out.Type = BinaryOp(opName)

			inner, err := x.DecodeRangedList(e.children, 2, 2)
			if err != nil {
				return out, err
			}

			out.Left = inner[0]
			out.Right = inner[1]

			return out, nil
		},
		func(in Binary, e *xmlElement, x *Xml) error {
			e.token.Attr = []xml.Attr{{
				Name: xml.Name{
					Local: "op",
				},
				Value: string(in.Type),
			}}
			left, err := x.Encode(in.Left)
			if err != nil {
				return err
			}
			e.addElement(left)
			right, err := x.Encode(in.Right)
			if err != nil {
				return err
			}
			e.addElement(right)
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Unary, error) {
			out := Unary{}

			opName := e.attr("op")
			if opName == "" {
				return out, fmt.Errorf("Unary op not given.")
			}
			out.Type = UnaryOp(opName)

			inner, err := x.DecodeRangedList(e.children, 1, 1)
			if err != nil {
				return out, err
			}

			out.Value = inner[0]

			return out, nil
		},
		func(in Unary, e *xmlElement, x *Xml) error {
			e.token.Attr = []xml.Attr{{
				Name: xml.Name{
					Local: "op",
				},
				Value: string(in.Type),
			}}
			encoded, err := x.Encode(in.Value)
			if err != nil {
				return err
			}
			e.addElement(encoded)
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Get, error) {
			out := Get{[]any{}}

			for _, c := range e.children {
				switch tt := c.token.(type) {
				case xml.CharData:
					nodes := strings.Split(string(tt), ",")
					for _, n := range nodes {
						out.Path = append(out.Path, strings.TrimSpace(n))
					}
				case xml.StartElement:
					decoded, err := x.Decode(xmlElement{
						token:    tt,
						children: c.children,
					})
					if err != nil {
						return out, err
					}
					out.Path = append(out.Path, decoded)
				}
			}

			return out, nil
		},
		func(in Get, e *xmlElement, x *Xml) error {
			for _, n := range in.Path {
				if expr, ok := n.(Expr); ok {
					encoded, err := x.Encode(expr)
					if err != nil {
						return nil
					}
					e.addElement(encoded)
				} else {
					asString, err := toString(n)
					if err != nil {
						return err
					}
					e.addNode(&xmlNode[any]{
						token: xml.CharData(asString),
					})
				}
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Set, error) {
			out := Set{[]any{}, nil}

			e.children.sequential([]nodeSequence{
				{
					name: "path",
					min:  1,
					max:  1,
					handle: func(e xmlElement, comments []xmlNode[xml.Comment]) error {
						for _, c := range e.children {
							switch tt := c.token.(type) {
							case xml.CharData:
								nodes := strings.Split(string(tt), ",")
								for _, n := range nodes {
									out.Path = append(out.Path, strings.TrimSpace(n))
								}
							case xml.StartElement:
								decoded, err := x.Decode(xmlElement{
									token:    tt,
									children: c.children,
								})
								if err != nil {
									return err
								}
								out.Path = append(out.Path, decoded)
							}
						}
						return nil
					},
				},
				{
					name: "value",
					min:  1,
					max:  1,
					handle: handleList(x, 1, func(inner []Expr) error {
						out.Value = inner[0]
						return nil
					}),
				},
			})

			return out, nil
		},
		func(in Set, e *xmlElement, x *Xml) error {

			paths := newXmlElement("path", xmlNodes{})
			for _, n := range in.Path {
				if expr, ok := n.(Expr); ok {
					encoded, err := x.Encode(expr)
					if err != nil {
						return nil
					}
					e.addElement(encoded)
				} else {
					asString, err := toString(n)
					if err != nil {
						return err
					}
					paths.addNode(&xmlNode[any]{
						token: xml.CharData(asString),
					})
				}
			}
			e.addElement(paths)

			value, err := x.Encode(in.Value)
			if err != nil {
				return err
			}
			e.addNamedElement("value", value.toNodes())

			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Invoke, error) {
			out := Invoke{
				Params: make(map[string]Expr),
			}

			functionName := e.attr("func")
			if functionName == "" {
				return out, fmt.Errorf("Invoke function not given.")
			}
			out.Function = functionName

			els := e.children.getElements()
			for _, el := range els {
				decoded, err := x.DecodeRangedList(el.children, 1, 1)
				if err != nil {
					return out, err
				}
				out.Params[el.token.Name.Local] = decoded[0]
			}

			return out, nil
		},
		func(in Invoke, e *xmlElement, x *Xml) error {
			e.token.Attr = []xml.Attr{{
				Name: xml.Name{
					Local: "func",
				},
				Value: in.Function,
			}}
			for key, value := range in.Params {
				valueEncoded, err := x.Encode(value)
				if err != nil {
					return err
				}
				e.addNamedElement(key, valueEncoded.toNodes())
			}
			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Define, error) {
			out := Define{
				Vars: make([]DefineVar, 0),
			}

			e.children.sequential([]nodeSequence{{
				name: "vars",
				min:  1,
				max:  -1,
				handle: func(e xmlElement, comments []xmlNode[xml.Comment]) error {
					for _, n := range e.children.getElements() {
						encoded, err := x.Decode(n)
						if err != nil {
							return nil
						}
						out.Vars = append(out.Vars, DefineVar{
							Name:  n.token.Name.Local,
							Value: encoded,
						})
					}
					return nil
				},
			}, {
				min: 1,
				max: 1,
				handle: handleList(x, 1, func(inner []Expr) error {
					out.Body = inner[0]
					return nil
				}),
			}})

			return out, nil
		},
		func(in Define, e *xmlElement, x *Xml) error {

			vars := newXmlElement("vars", xmlNodes{})

			for _, v := range in.Vars {
				valueEncoded, err := x.Encode(v.Value)
				if err != nil {
					return err
				}
				vars.addNamedElement(v.Name, valueEncoded.toNodes())
			}

			e.addElement(vars)

			body, err := x.Encode(in.Body)
			if err != nil {
				return err
			}
			e.addElement(body)

			return nil
		},
	),

	NewXmlEntry(
		func(e xmlElement, x *Xml) (Template, error) {
			out := Template{
				Vars: make(map[string]Expr),
			}

			format := e.attr("format")
			if format != "" {
				out.Format = Constant{format}
			}

			e.children.sequential([]nodeSequence{{
				name: "format",
				min:  0,
				max:  1,
				handle: handleList(x, 1, func(inner []Expr) error {
					out.Format = inner[0]
					return nil
				}),
			}, {
				name: "vars",
				min:  0,
				max:  -1,
				handle: func(e xmlElement, comments []xmlNode[xml.Comment]) error {
					for _, n := range e.children.getElements() {
						encoded, err := x.Decode(n)
						if err != nil {
							return nil
						}
						out.Vars[n.token.Name.Local] = encoded
					}
					return nil
				},
			}})

			return out, nil
		},
		func(in Template, e *xmlElement, x *Xml) error {
			if formatConstant, ok := in.Format.(Constant); ok {
				if formatString, ok := formatConstant.Value.(string); ok {
					e.token.Attr = []xml.Attr{{
						Name: xml.Name{
							Local: "format",
						},
						Value: formatString,
					}}
				}
			}
			if e.token.Attr == nil || len(e.token.Attr) == 0 {
				formatEncoded, err := x.Encode(in.Format)
				if err != nil {
					return err
				}
				e.addNamedElement("format", formatEncoded.toNodes())
			}

			vars := newXmlElement("vars", xmlNodes{})

			for k, v := range in.Vars {
				valueEncoded, err := x.Encode(v)
				if err != nil {
					return err
				}
				vars.addNamedElement(k, valueEncoded.toNodes())
			}

			e.addElement(vars)

			return nil
		},
	),
}

Functions

func MarshalXML

func MarshalXML(e *xml.Encoder, expr Expr) error

func Run

func Run(e Expr, state *State) (any, error)

Compiles and runs the given expression against the given state and returns the result or the error.

func ToXmlString

func ToXmlString(expr Expr, indent string) (string, error)

Types

type And

type And struct {
	Conditions []Expr
}

And is an expression that resolves to a bool value, true if all inner conditions are true and false if any of the inner conditions are false.

func (And) Name

func (e And) Name() string

type AndCompiled

type AndCompiled[CE CompiledExpr] struct {
	Conditions []CE
}

func AndCompile

func AndCompile[CE CompiledExpr](c *Compiler[CE], e And) (AndCompiled[CE], error)

type Assert

type Assert struct {
	Expect Expr
	Error  Expr
}

Assert is an expression which is only valid within a Body. Based on configuration it will either behave like an error and cease all processing and return the assertion error, or it may just log the assertion.

func (Assert) Name

func (e Assert) Name() string

type AssertCompiled

type AssertCompiled[CE CompiledExpr] struct {
	Expect CE
	Error  CE
}

func AssertCompile

func AssertCompile[CE CompiledExpr](c *Compiler[CE], e Assert) (AssertCompiled[CE], error)

type Binary

type Binary struct {
	Left  Expr
	Type  BinaryOp
	Right Expr
}

Binary is an expression which performs a math operation on two expressions and returns a result. Implementations dictate which types are supported and if the user can override the default binary operation logic. If the type of the left and right expressions are different, the resulting type will be one of the types that makes the most sense for the given operation.

func (Binary) Name

func (e Binary) Name() string

type BinaryCompiled

type BinaryCompiled[CE CompiledExpr] struct {
	Left  CE
	Type  BinaryOp
	Right CE
}

func BinaryCompile

func BinaryCompile[CE CompiledExpr](c *Compiler[CE], e Binary) (BinaryCompiled[CE], error)

type BinaryOp

type BinaryOp string
const (
	ADD    BinaryOp = "+"
	SUB    BinaryOp = "-"
	MUL    BinaryOp = "*"
	DIV    BinaryOp = "/"
	MOD    BinaryOp = "%"
	POW    BinaryOp = "^^"
	OR     BinaryOp = "|"
	AND    BinaryOp = "&"
	XOR    BinaryOp = "^"
	LSHIFT BinaryOp = "<<"
	RSHIFT BinaryOp = ">>"
	MAX    BinaryOp = "max"
	MIN    BinaryOp = "min"
	GCD    BinaryOp = "gcd"
	ATAN2  BinaryOp = "atan2"
)

type Body

type Body struct {
	Lines []Expr
}

Body is an expression that can have multiple sequential expressions. A Body is the only valid place for Return, Throw, Assert, and Break expressions.

func (Body) IsEmpty

func (e Body) IsEmpty() bool

func (Body) Name

func (e Body) Name() string

type BodyCompiled

type BodyCompiled[CE CompiledExpr] struct {
	Lines []CE
}

func BodyCompile

func BodyCompile[CE CompiledExpr](c *Compiler[CE], e Body) (BodyCompiled[CE], error)

type Break

type Break struct{}

Break is an expression which is only valid within a Body inside of a Loop. When detected the inner loop expressions after it are skipped and processing is resumed after the loop.

func (Break) Name

func (e Break) Name() string

type Compare

type Compare struct {
	Left  Expr
	Type  CompareOp
	Right Expr
}

Compare is an expression which compares two expressions with the given operation and returns a bool value with the result. Implementations dictate which types are supported and if the user can override the default comparison logic.

func (Compare) Name

func (e Compare) Name() string

type CompareCompiled

type CompareCompiled[CE CompiledExpr] struct {
	Left  CE
	Type  CompareOp
	Right CE
}

func CompareCompile

func CompareCompile[CE CompiledExpr](c *Compiler[CE], e Compare) (CompareCompiled[CE], error)

type CompareOp

type CompareOp string
const (
	EQ  CompareOp = "="
	NEQ CompareOp = "!="
	LT  CompareOp = "<"
	GT  CompareOp = ">"
	LTE CompareOp = "<="
	GTE CompareOp = ">="
)

type Compile

type Compile[CE CompiledExpr] func(e Expr, c *Compiler[CE]) CE

A function which takes an expression and compiler and returns the CompiledExpr.

type CompileTyped

type CompileTyped[E Expr, CE CompiledExpr] func(e E, c *Compiler[CE]) CE

A typed compile function for a better developer experience.

type CompiledExpr

type CompiledExpr interface {
	// The compiled expression.
	Expr() Expr
	// The compilation error, if any.
	Error() error
}

The common interface that expressions can be compiled to. It contains the expression that was compiled and a compilation error if any were found.

type Compiler

type Compiler[CE CompiledExpr] struct {
	// The map of entries (keyed by Expr name) supported in this compiler.
	Entries map[string]CompilerEntry[CE]
	// A function which returns the error form of the CompiledExpr type.
	CreateError CompilerError[CE]
}

A compiler takes an expression and compiles it down to a target CompiledExpr.

The standard InspectExpr compiler for standard expressions.

var RunC *Compiler[RunExpr] = CreateRunCompiler(func(c *Compiler[RunExpr]) {
	c.Defines(RunCompilerEntries)
})

The standard RunExpr compiler for standard expressions.

func CreateCompiler

func CreateCompiler[EC CompiledExpr](createError CompilerError[EC], with func(c *Compiler[EC])) *Compiler[EC]

Allocates and allows manipulation of a new compiler for CompiledExpr before returning.

func CreateInspectCompiler

func CreateInspectCompiler(with func(c *Compiler[InspectExpr])) *Compiler[InspectExpr]

Allocates and allows manipulation of a new compiler for InspectExpr before returning it.

func CreateRunCompiler

func CreateRunCompiler(with func(c *Compiler[RunExpr])) *Compiler[RunExpr]

Allocates and allows manipulation of a new compiler for RunExpr before returning it.

func NewCompiler

func NewCompiler[EC CompiledExpr](createError CompilerError[EC]) *Compiler[EC]

Allocates a new compiler with the given error creation function.

func NewInspectCompiler

func NewInspectCompiler() *Compiler[InspectExpr]

Allocates a new compiler for InspectExpr that doesn't contain any expression compiler entries.

func NewRunCompiler

func NewRunCompiler() *Compiler[RunExpr]

Allocates a new compiler for RunExpr that doesn't contain any expression compiler entries.

func (*Compiler[EC]) Compile

func (c *Compiler[EC]) Compile(e Expr) EC

Compiles the given expression to the CompiledExpr type. If there was an error compiling the returned CompiledExpr will have a non-nil error.

func (*Compiler[CE]) CompileList

func (c *Compiler[CE]) CompileList(list []Expr) ([]CE, error)

Compiles a slice of expressions into a slice of CompiledExpr. If any of the items generated an error then compilation stops and the error and the generated slice up until that point is returned. This will always return a non-nil slice even if the given slice is nil.

func (*Compiler[CE]) CompileMap

func (c *Compiler[CE]) CompileMap(m map[string]Expr) (map[string]CE, error)

Compiles a map of expressions into a map of CompiledExpr. If any of the items generated an error then compilation stops and the error and the generated map up until that point is returned. This will always return a non-nil map even if the given map is nil.

func (*Compiler[EC]) CompileMaybe

func (c *Compiler[EC]) CompileMaybe(e Expr) EC

Compiles the given expression if it's non-nil. If it is nil then an empty CompiledExpr is returned. Users of optional compilation need to check the state of the CompiledExpr before attempting to use it.

func (*Compiler[CE]) CompilePath

func (c *Compiler[CE]) CompilePath(path []any) ([]CE, error)

Compiles a slice of values which can be raw values or expressions into a slice of CompiledExpr. If any of the items generated an error then compilation stops and the error and the generated slice up until that point is returned. This will always return a non-nil slice even if the given slice is nil.

func (*Compiler[CE]) Define

func (c *Compiler[CE]) Define(entry CompilerEntry[CE])

Adds an entry (Expr, Compile pair) to the compiler for a single expression.

func (*Compiler[CE]) Defines

func (c *Compiler[CE]) Defines(entries []CompilerEntry[CE])

Adds entries (Expr, Compile pairs) to the compiler for multiple expressions.

type CompilerEntry

type CompilerEntry[CE CompiledExpr] struct {
	// The expression the compile function can handle.
	Expr Expr
	// A compile function for the expression type which generates a CompiledExpr.
	Compile Compile[CE]
}

An entry in the compiler which is an expression - compile function pair.

func CreateEntry

func CreateEntry[E Expr, CE CompiledExpr](compile CompileTyped[E, CE]) CompilerEntry[CE]

Creates a compiler entry for a given expression type and compilation function.

type CompilerError

type CompilerError[CE CompiledExpr] func(e Expr, err error) CE

A function which generates an error form of the CompiledExpr type.

type Constant

type Constant struct {
	Value any
}

Constant is an expression which returns a constant value.

func (Constant) Name

func (e Constant) Name() string

type Define

type Define struct {
	Vars []DefineVar
	Body Expr
}

Define is an expression which creates a new variable scope and defines new variables that can be accessed and updated within the Body of the define.

func (Define) Name

func (e Define) Name() string

type DefineCompiled

type DefineCompiled[CE CompiledExpr] struct {
	Vars []DefineVarCompiled[CE]
	Body CE
}

func DefineCompile

func DefineCompile[CE CompiledExpr](c *Compiler[CE], e Define) (DefineCompiled[CE], error)

type DefineVar

type DefineVar struct {
	Name  string
	Value Expr
}

type DefineVarCompiled

type DefineVarCompiled[CE CompiledExpr] struct {
	Name  string
	Value CE
}

type Expr

type Expr interface {
	Name() string
}

An Expr represents a node in an abstract syntax tree. The have names so a compile, marshal, or unmarshal can know the node type and from there determine how to proceed with processing.

func FromXmlString

func FromXmlString(x string) (Expr, error)

func UnmarshalXML

func UnmarshalXML(d *xml.Decoder) (Expr, error)

type ExprError

type ExprError struct {
	// contains filtered or unexported fields
}

An error that retains the expression it happened on and in inner exception. This may end up being a linked list of errors which should identify where in the tree the error occurred.

func Stacktrace

func Stacktrace(err error) []ExprError

Returns the stack trace for the given error, in order from deepest

func (ExprError) Error

func (ee ExprError) Error() string

func (ExprError) Root

func (ee ExprError) Root() error

type Function

type Function struct {
	ReturnType     reflect.Type
	Arguments      []FunctionArg
	Implementation reflect.Value
}

func NewExprFunction

func NewExprFunction(run *Runtime, name string, args []FunctionArg, expr Expr) Function

func NewNativeFunction

func NewNativeFunction(argNames []string, impl any) Function

type FunctionArg

type FunctionArg struct {
	Name string
	Type reflect.Type
}

type Get

type Get struct {
	Path []any
}

Get is an expression which retrieves a value from the current state. It will start at the current scope and make its way to the base data of the state and finally to global state until it finds a variable with the same name as the first element in the path. The path can be a sequence of int or strings constants or even Exprs to be evaluated. Get will walk along the value based on the path to get the final value.

func (Get) Name

func (e Get) Name() string

type GetCompiled

type GetCompiled[CE CompiledExpr] struct {
	Path []CE
}

func GetCompile

func GetCompile[CE CompiledExpr](c *Compiler[CE], e Get) (GetCompiled[CE], error)

type If

type If struct {
	Cases []IfCase
	Else  Expr
}

If is an expression with one or many condition & body pairs and optionally a fall through expression. The first case which has a true condition gets its Then processed, if no cases are true and an Else expression is given that is processed.

func (If) Name

func (e If) Name() string

type IfCase

type IfCase struct {
	Condition Expr
	Then      Expr
}

type IfCaseCompiled

type IfCaseCompiled[CE CompiledExpr] struct {
	Condition CE
	Then      CE
}

type IfCompiled

type IfCompiled[CE CompiledExpr] struct {
	Cases []IfCaseCompiled[CE]
	Else  CE
}

func IfCompile

func IfCompile[CE CompiledExpr](c *Compiler[CE], e If) (IfCompiled[CE], error)

type InspectExpr

type InspectExpr struct {
	// Tries to determine the possible return types for this expression and the given state.
	ReturnType func(state *State) Types
	// contains filtered or unexported fields
}

An expression compiled into something that can provide execution metadata.

func Inspect

func Inspect(e Expr) InspectExpr

Compiles the given expression using the standard compiler.

func (InspectExpr) Error

func (e InspectExpr) Error() error

func (InspectExpr) Expr

func (e InspectExpr) Expr() Expr

type Invoke

type Invoke struct {
	Function string
	Params   map[string]Expr
}

Invoke is an expression which finds a defined function with the given name and invokes it passing along the parameters specified. If a parameter to the function is not specified the default value for that type will be supplied.

func (Invoke) Name

func (e Invoke) Name() string

type InvokeCompiled

type InvokeCompiled[CE CompiledExpr] struct {
	Function string
	Params   map[string]CE
}

func InvokeCompile

func InvokeCompile[CE CompiledExpr](c *Compiler[CE], e Invoke) (InvokeCompiled[CE], error)

type Loop

type Loop struct {
	Start Expr
	While Expr
	Next  Expr
	Then  Expr
}

Loop is an expression which performs a loop. All inner expressions are optional. A loop creates a new variable scope. If a Set expression is specified that is processed first at the beginning of the loop. If a While expression is specified that is processed and if it returns a false value then looping ceases. If a Then expression is specified, that is processed if While returned true (or is not present). The Then expression catches Breaks called from within and that stops looping immediately as well. Finally if a Next expression is specified it's processed after Then would be. This format allows for various types of looping styles.

func (Loop) Name

func (e Loop) Name() string

type LoopCompiled

type LoopCompiled[CE CompiledExpr] struct {
	Start CE
	While CE
	Next  CE
	Then  CE
}

func LoopCompile

func LoopCompile[CE CompiledExpr](c *Compiler[CE], e Loop) (LoopCompiled[CE], error)

type Not

type Not struct {
	Condition Expr
}

Not is an expression that resolves to a bool value, it negates the bool value of the inner condition.

func (Not) Name

func (e Not) Name() string

type NotCompiled

type NotCompiled[CE CompiledExpr] struct {
	Condition CE
}

func NotCompile

func NotCompile[CE CompiledExpr](c *Compiler[CE], e Not) (NotCompiled[CE], error)

type Or

type Or struct {
	Conditions []Expr
}

Or is an expression that resolves to a bool value, true if any of the inner conditions are true and false if all of the inner conditions are false.

func (Or) Name

func (e Or) Name() string

type OrCompiled

type OrCompiled[CE CompiledExpr] struct {
	Conditions []CE
}

func OrCompile

func OrCompile[CE CompiledExpr](c *Compiler[CE], e Or) (OrCompiled[CE], error)

type Ref

type Ref struct {
	Value  reflect.Value
	Type   reflect.Type
	Path   []string
	Parent *Ref
	Error  error
	Exists bool
}

func (Ref) Clone

func (ref Ref) Clone() Ref

func (Ref) Concrete

func (ref Ref) Concrete()

func (*Ref) GetError

func (ref *Ref) GetError() error

func (*Ref) Ref

func (ref *Ref) Ref(next any) *Ref

func (Ref) Save

func (ref Ref) Save() error

func (*Ref) Set

func (ref *Ref) Set(value any) error

func (Ref) Valid

func (ref Ref) Valid() bool

type Return

type Return struct {
	Value Expr
}

Return is an expression which is only valid within a Body. It will cease all processing of expressions in the tree or function and optionally can return a value.

func (Return) Name

func (e Return) Name() string

type ReturnCompiled

type ReturnCompiled[CE CompiledExpr] struct {
	Value CE
}

func ReturnCompile

func ReturnCompile[CE CompiledExpr](c *Compiler[CE], e Return) (ReturnCompiled[CE], error)

type RunExpr

type RunExpr struct {
	// Runs the expression against the state and returns the result and if any errors occurred.
	Run func(state *State) (any, error)
	// contains filtered or unexported fields
}

An expression compiled into something that can run on a given program state.

func (RunExpr) Error

func (e RunExpr) Error() error

func (RunExpr) Expr

func (e RunExpr) Expr() Expr

type Runtime

type Runtime struct {
	Data              Ref
	Funcs             map[string]Function
	Epsilon           float64
	Insensitive       bool
	InsensitiveFields bool
	MaxIterations     int
	AssertionLimit    int
}

func NewRuntime

func NewRuntime(globalData any) *Runtime

func (*Runtime) AddSystemFunc

func (run *Runtime) AddSystemFunc(name string, argNames []string, impl any) Function

func (*Runtime) AddUserFunc

func (run *Runtime) AddUserFunc(name string, args []FunctionArg, expr Expr) Function

func (Runtime) Clone

func (run Runtime) Clone() *Runtime

func (*Runtime) NewDetachedState

func (run *Runtime) NewDetachedState(data any) *State

func (*Runtime) NewState

func (run *Runtime) NewState(data any) *State

type Set

type Set struct {
	Path  []any
	Value Expr
}

Set is an expression which updates the current state. It will start at the current scope and make its way to the base data of the state and finally to global state until it finds a variable with the same name as the first element in the path. The path can be a sequence of int or strings constants or even Exprs to be evaluated. Set will walk along the value based on the path to set the final value. If the path is not compatible with the structure of the current state and global data then an error will be returned. Set should perform all necessary initialization of values before applying the new value. This may create maps, slices, pointer values, or change the size of a slice if a part of the path is an index outside of the slice's current length.

func (Set) Name

func (e Set) Name() string

type SetCompiled

type SetCompiled[CE CompiledExpr] struct {
	Path  []CE
	Value CE
}

func SetCompile

func SetCompile[CE CompiledExpr](c *Compiler[CE], e Set) (SetCompiled[CE], error)

type State

type State struct {
	Data       Ref
	Scopes     []*Ref
	Assertions []ExprError
	Runtime    *Runtime
}

func (*State) Assert

func (state *State) Assert(assertion ExprError) error

func (*State) EnterScope

func (state *State) EnterScope() *Ref

func (*State) ExitScope

func (state *State) ExitScope()

func (*State) Ref

func (state *State) Ref(next any) *Ref

type Switch

type Switch struct {
	Value   Expr
	Cases   []SwitchCase
	Default Expr
}

Switch is an expression that evaluates a value and compares it against expected values and if its equivalent then the Then expression is processed. If value never matches an expected value then the Default expression, if given, is processed.

func (Switch) Name

func (e Switch) Name() string

type SwitchCase

type SwitchCase struct {
	Expected []Expr
	Then     Expr
}

type SwitchCaseCompiled

type SwitchCaseCompiled[CE CompiledExpr] struct {
	Expected []CE
	Then     CE
}

type SwitchCompiled

type SwitchCompiled[CE CompiledExpr] struct {
	Value   CE
	Cases   []SwitchCaseCompiled[CE]
	Default CE
}

func SwitchCompile

func SwitchCompile[CE CompiledExpr](c *Compiler[CE], e Switch) (SwitchCompiled[CE], error)

type Template

type Template struct {
	Format Expr
	Vars   map[string]Expr
}

Template is an expression which returns a string with variables injected into it.

func (Template) Name

func (e Template) Name() string

type TemplateCompiled

type TemplateCompiled[CE CompiledExpr] struct {
	Vars   map[string]CE
	Format CE
}

func TemplateCompile

func TemplateCompile[CE CompiledExpr](c *Compiler[CE], e Template) (TemplateCompiled[CE], error)

type Throw

type Throw struct {
	Error Expr
}

Throw is an expression which is only valid within a Body. It will cease all processing of expressions in the entire tree unless its caught.

func (Throw) Name

func (e Throw) Name() string

type ThrowCompiled

type ThrowCompiled[CE CompiledExpr] struct {
	Error CE
}

func ThrowCompile

func ThrowCompile[CE CompiledExpr](c *Compiler[CE], e Throw) (ThrowCompiled[CE], error)

type Try

type Try struct {
	Body    Expr
	Catch   Expr
	Finally Expr
}

Try is an expression which is only valid within a Body. It will process the body and if that generates an error then Catch will be processed if it is given with the error string placed in the error value in a new context. If Finally is given its always processed last, even if Catch throws an error.

func (Try) Name

func (e Try) Name() string

type TryCompiled

type TryCompiled[CE CompiledExpr] struct {
	Body    CE
	Catch   CE
	Finally CE
}

func TryCompile

func TryCompile[CE CompiledExpr](c *Compiler[CE], e Try) (TryCompiled[CE], error)

type Types

type Types map[reflect.Type]struct{}

A set of types.

func (Types) Add

func (t Types) Add(newType reflect.Type)

Adds the type to the set if it doesn't exist already.

func (Types) AddTypes

func (t Types) AddTypes(types Types)

Adds the given set of types to this set of types if they don't exist already.

func (Types) ToSlice

func (t Types) ToSlice() []reflect.Type

Returns a slice of the types found in this set.

type Unary

type Unary struct {
	Type  UnaryOp
	Value Expr
}

Unary is an expression which performs a math operation on one expression and returns a result. Implementations dictate which types are supported and if the user can override the default binary operation logic. If the type of the left and right expressions are different, the resulting type will be one of the types that makes the most sense for the given operation.

func (Unary) Name

func (e Unary) Name() string

type UnaryCompiled

type UnaryCompiled[CE CompiledExpr] struct {
	Type  UnaryOp
	Value CE
}

func UnaryCompile

func UnaryCompile[CE CompiledExpr](c *Compiler[CE], e Unary) (UnaryCompiled[CE], error)

type UnaryOp

type UnaryOp string
const (
	NEG   UnaryOp = "-"
	NOT   UnaryOp = "~"
	ABS   UnaryOp = "||"
	COS   UnaryOp = "cos"
	SIN   UnaryOp = "sin"
	TAN   UnaryOp = "tan"
	ACOS  UnaryOp = "acos"
	ASIN  UnaryOp = "asin"
	ATAN  UnaryOp = "atan"
	FLOOR UnaryOp = "floor"
	CEIL  UnaryOp = "ceil"
	ROUND UnaryOp = "round"
	SQRT  UnaryOp = "sqrt"
	CBRT  UnaryOp = "cbrt"
	SQR   UnaryOp = "sqr"
	LN    UnaryOp = "ln"
	LOG2  UnaryOp = "log2"
	LOG10 UnaryOp = "log10"
	TRUNC UnaryOp = "trunc"
)

type Xml

type Xml struct {
	Entries   map[string]XmlEntry
	Types     map[string]reflect.Type
	NameToTag func(string) string
}
var XmlInstance *Xml = CreateXML(func(x *Xml) {
	x.Defines(XmlEntries)

	x.Types["int"] = reflect.TypeOf(int(0))
	x.Types["int8"] = reflect.TypeOf(int8(0))
	x.Types["int16"] = reflect.TypeOf(int16(0))
	x.Types["int32"] = reflect.TypeOf(int32(0))
	x.Types["int64"] = reflect.TypeOf(int64(0))
	x.Types["uint"] = reflect.TypeOf(uint(0))
	x.Types["uint8"] = reflect.TypeOf(uint8(0))
	x.Types["uint16"] = reflect.TypeOf(uint16(0))
	x.Types["uint32"] = reflect.TypeOf(uint32(0))
	x.Types["uint64"] = reflect.TypeOf(uint64(0))
	x.Types["bool"] = reflect.TypeOf(true)
	x.Types["string"] = reflect.TypeOf("")
	x.Types["float32"] = reflect.TypeOf(float32(0))
	x.Types["float64"] = reflect.TypeOf(float64(0))
})

func CreateXML

func CreateXML(with func(x *Xml)) *Xml

func NewXml

func NewXml() *Xml

func (*Xml) Decode

func (x *Xml) Decode(n xmlElement) (Expr, error)

func (*Xml) DecodeList

func (x *Xml) DecodeList(n xmlNodes) ([]Expr, error)

func (*Xml) DecodeRangedList

func (x *Xml) DecodeRangedList(n xmlNodes, min int, max int) ([]Expr, error)

func (*Xml) Define

func (x *Xml) Define(entry XmlEntry)

func (*Xml) Defines

func (x *Xml) Defines(entries []XmlEntry)

func (*Xml) Encode

func (x *Xml) Encode(e Expr) (*xmlElement, error)

func (*Xml) EncodeElement

func (x *Xml) EncodeElement(e *xml.Encoder, expr Expr) (*xmlElement, error)

func (*Xml) EncodeList

func (x *Xml) EncodeList(exprs []Expr) (xmlNodes, error)

func (*Xml) FromString

func (x *Xml) FromString(input string) (Expr, error)

func (*Xml) Marshal

func (x *Xml) Marshal(e *xml.Encoder, expr Expr) error

func (*Xml) ToString

func (x *Xml) ToString(expr Expr, indent string) (string, error)

func (*Xml) Unmarshal

func (x *Xml) Unmarshal(d *xml.Decoder) (Expr, error)

type XmlDecodeError

type XmlDecodeError struct {
	Element xmlElement
	Err     error
}

func (XmlDecodeError) Error

func (e XmlDecodeError) Error() string

type XmlEncodeError

type XmlEncodeError struct {
	Expr Expr
	Err  error
}

func (XmlEncodeError) Error

func (e XmlEncodeError) Error() string

type XmlEntry

type XmlEntry struct {
	Expr   Expr
	Decode func(out *Expr, n xmlElement, x *Xml) error
	Encode func(in Expr, n *xmlElement, x *Xml) error
}

func NewXmlEntry

func NewXmlEntry[E Expr](
	decode func(n xmlElement, x *Xml) (E, error),
	encode func(in E, n *xmlElement, x *Xml) error,
) XmlEntry

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL