Documentation ¶
Index ¶
- Variables
- func MarshalXML(e *xml.Encoder, expr Expr) error
- func Run(e Expr, state *State) (any, error)
- func ToXmlString(expr Expr, indent string) (string, error)
- type And
- type AndCompiled
- type Assert
- type AssertCompiled
- type Binary
- type BinaryCompiled
- type BinaryOp
- type Body
- type BodyCompiled
- type Break
- type Compare
- type CompareCompiled
- type CompareOp
- type Compile
- type CompileTyped
- type CompiledExpr
- type Compiler
- func CreateCompiler[EC CompiledExpr](createError CompilerError[EC], with func(c *Compiler[EC])) *Compiler[EC]
- func CreateInspectCompiler(with func(c *Compiler[InspectExpr])) *Compiler[InspectExpr]
- func CreateRunCompiler(with func(c *Compiler[RunExpr])) *Compiler[RunExpr]
- func NewCompiler[EC CompiledExpr](createError CompilerError[EC]) *Compiler[EC]
- func NewInspectCompiler() *Compiler[InspectExpr]
- func NewRunCompiler() *Compiler[RunExpr]
- func (c *Compiler[EC]) Compile(e Expr) EC
- func (c *Compiler[CE]) CompileList(list []Expr) ([]CE, error)
- func (c *Compiler[CE]) CompileMap(m map[string]Expr) (map[string]CE, error)
- func (c *Compiler[EC]) CompileMaybe(e Expr) EC
- func (c *Compiler[CE]) CompilePath(path []any) ([]CE, error)
- func (c *Compiler[CE]) Define(entry CompilerEntry[CE])
- func (c *Compiler[CE]) Defines(entries []CompilerEntry[CE])
- type CompilerEntry
- type CompilerError
- type Constant
- type Define
- type DefineCompiled
- type DefineVar
- type DefineVarCompiled
- type Expr
- type ExprError
- type Function
- type FunctionArg
- type Get
- type GetCompiled
- type If
- type IfCase
- type IfCaseCompiled
- type IfCompiled
- type InspectExpr
- type Invoke
- type InvokeCompiled
- type Loop
- type LoopCompiled
- type Not
- type NotCompiled
- type Or
- type OrCompiled
- type Ref
- type Return
- type ReturnCompiled
- type RunExpr
- type Runtime
- func (run *Runtime) AddSystemFunc(name string, argNames []string, impl any) Function
- func (run *Runtime) AddUserFunc(name string, args []FunctionArg, expr Expr) Function
- func (run Runtime) Clone() *Runtime
- func (run *Runtime) NewDetachedState(data any) *State
- func (run *Runtime) NewState(data any) *State
- type Set
- type SetCompiled
- type State
- type Switch
- type SwitchCase
- type SwitchCaseCompiled
- type SwitchCompiled
- type Template
- type TemplateCompiled
- type Throw
- type ThrowCompiled
- type Try
- type TryCompiled
- type Types
- type Unary
- type UnaryCompiled
- type UnaryOp
- type Xml
- func (x *Xml) Decode(n xmlElement) (Expr, error)
- func (x *Xml) DecodeList(n xmlNodes) ([]Expr, error)
- func (x *Xml) DecodeRangedList(n xmlNodes, min int, max int) ([]Expr, error)
- func (x *Xml) Define(entry XmlEntry)
- func (x *Xml) Defines(entries []XmlEntry)
- func (x *Xml) Encode(e Expr) (*xmlElement, error)
- func (x *Xml) EncodeElement(e *xml.Encoder, expr Expr) (*xmlElement, error)
- func (x *Xml) EncodeList(exprs []Expr) (xmlNodes, error)
- func (x *Xml) FromString(input string) (Expr, error)
- func (x *Xml) Marshal(e *xml.Encoder, expr Expr) error
- func (x *Xml) ToString(expr Expr, indent string) (string, error)
- func (x *Xml) Unmarshal(d *xml.Decoder) (Expr, error)
- type XmlDecodeError
- type XmlEncodeError
- type XmlEntry
Constants ¶
This section is empty.
Variables ¶
var ASSERT_ERROR = errors.New("Assertion error")
var BREAK = errors.New("Break")
var ERROR = errors.New("Error")
var ErrorEndExpected = errors.New("End of element not found")
var ErrorEndUnexpected = errors.New("End of element")
var ErrorWrongElement = errors.New("Wrong element")
var FUNCTION_NOT_FOUND = errors.New("Function not found")
var INDEX_OUTSIDE_ARRAY = errors.New("Index outside of array")
var INVALID_BINARY = errors.New("Invalid binary operation for types")
var INVALID_BINARY_TYPE = errors.New("Invalid type for binary operation")
var INVALID_BOOL_TYPE = errors.New("Value could not be converted to bool")
var INVALID_COMPARE_TYPE = errors.New("Types incomparable")
var INVALID_COMPARISON = errors.New("Invalid comparison for types")
var INVALID_REF = errors.New("Undefined reference")
var INVALID_UNARY = errors.New("Invalid unary operation for type")
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.
var MAX_ITERATIONS = errors.New("Max iterations met")
var RETURN = errors.New("Return")
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.
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 ¶
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.
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 ¶
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.
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 ¶
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.
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.
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.
type Compare ¶
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.
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 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.
var InspectC *Compiler[InspectExpr] = CreateInspectCompiler(func(c *Compiler[InspectExpr]) { c.Defines(InspectCompilerEntries) })
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 ¶
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 ¶
Allocates a new compiler for RunExpr that doesn't contain any expression compiler entries.
func (*Compiler[EC]) Compile ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
type Define ¶
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.
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 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 ¶
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 ¶
Returns the stack trace for the given error, in order from deepest
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 ¶
type FunctionArg ¶
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.
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 ¶
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.
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 ¶
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.
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 ¶
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.
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.
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.
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 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.
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.
type Runtime ¶
type Runtime struct { Data Ref Funcs map[string]Function Epsilon float64 Insensitive bool InsensitiveFields bool MaxIterations int AssertionLimit int }
func NewRuntime ¶
func (*Runtime) AddSystemFunc ¶
func (*Runtime) AddUserFunc ¶
func (run *Runtime) AddUserFunc(name string, args []FunctionArg, expr Expr) Function
func (*Runtime) NewDetachedState ¶
type Set ¶
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.
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 ¶
func (*State) EnterScope ¶
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.
type SwitchCase ¶
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 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.
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 ¶
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.
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 ¶
A set of types.
type Unary ¶
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.
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 (*Xml) DecodeList ¶
func (*Xml) DecodeRangedList ¶
func (*Xml) EncodeElement ¶
func (*Xml) EncodeList ¶
type XmlDecodeError ¶
type XmlDecodeError struct { Element xmlElement Err error }
func (XmlDecodeError) Error ¶
func (e XmlDecodeError) Error() string
type XmlEncodeError ¶
func (XmlEncodeError) Error ¶
func (e XmlEncodeError) Error() string