adz

package module
v0.0.0-...-de001c7 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2025 License: MIT Imports: 20 Imported by: 0

README

Coverage Status Go ReportCard GoDoc

ADZ

ADZ or adzlang is a Tcl-like scripting language. Similar in purpose to Tcl's original purpose, the idea is to provide an easy-to-bind scripting langauge and shell for Golang.

The general language parsing/lexing rules of Tcl applies to ADZ. Where ADZ differs is the implementation of the built-in commands and a few parsing corner cases.

ADZ does not in anyway aim to be compatible with Tcl. Tcl's ruleset and general idea is just easy to adapt and reuse.

Below is the Octologue from Tcl, modified to be true for ADZ.

Example: Adding a Command to ADZ

Initializing and adding a command to an ADZ interpreter is easy.

Currently by default the full base standard library of commands is added when an ADZ interpretter is initialized.

  interp := adz.NewInterp()
  interp.Procs = make(map[string]adz.Proc)
  interp.Procs["foo"] = func(interp *adz.Interp, args []*adz.Token) (*adz.Token, error) {
  	return adz.NewTokenString("bar"), nil
  }

The above golang code initializes an ADZ interpreter, removes all the base commands, then sets the command "foo" to the anonymous func which will always return bar.

	out, err := interp.ExecString(`foo`)
	fmt.Println(out.String, err)

The above will print "bar ".

Octologue

Script

A script is composed of commands delimited by newlines or semicolons, and a command is composed of words delimited by whitespace.

Evaluation

Substitutions in each word are processed, and the first word of each command is used to locate a routine, which is then called with the remaining words as its arguments.

ADZ does not (yet) support {*} argument expansion.

Comment

If # is encountered when the name of a command is expected, it and the subsequent characters up to the next newline are ignored, except that a newline preceded by an odd number of \ characters does not terminate the comment.

$varname

Replaced by the value of the variable named varname, which is a sequence of one or more letters, digits, or underscore characters, or namespace separators. If varname is enclosed in braces, it is composed of all the characters between the braces.

\char

Replaced with the character following char, except when char is a, b, f, n, t, r, v, which respectively signify the unicode characters audible alert (7), backspace (8), form feed (c), newline (a), carriage return (d), tab (9), and vertical tab (b), respectively. Additionally, when char is x or u, it represents a unicode character by 2 hexadecimal digits, or 1 or more hexadecimal digits, respectively.

Brackets

A script may be embedded at any position of a word by enclosing it in brackets. The embedded script is passed verbatim to the interpreter for execution and the result is inserted in place of the script and its enclosing brackets. The result of a script is the result of the last routine in the script.

Quotes

In a word enclosed in quotes, whitespace and semicolons have no special meaning.

Braces

In a word enclosed in braces, whitespace, semicolons, $, brackets, and \ have no special meaning, except that \newline substitution is performed when the newline character is preceded by an odd number of \ characters. Any nested opening brace character must be paired with a subsequent matching closing brace character. An opening or closing brace character preceded by an odd number of \ characters is not used to pair braces.

Intended Uses

MCUs

Currently, my main target for ADZ is as a commandline shell for an RP2040 based pocket-computer. Something akin to DOS.

For this reason I'm trying to keep memory usage really low. Currently the main underlying storage are strings and I may have to rework the whole code base and change over to byte slices for memory efficiency purposes--golang passes strings by value, so it doesn't take much for many many copies of the same string to be in memory. For the most part strings are passed around within a struct that is referenced by a pointer and this helps limit memory use. That said, since running on a microcontroller is the main goal, all other considerations are secondary.

Distributed, Interruptable Interpreter

I'd also like to use ADZ as glue-logic for passing around "scripts" between microservices. This isn't as begging-for-RCE as it sounds. With a little addtional work, the ADZ interpreter can be fully serialized and saved to disk, sent over the wire, or be backed by a database like badgerdb.

Since the interpreter is a set of builtin commands, text-based procedures, and text-based variables, serializing the interpreter is relatively easy, as long as you don't want to do it while a command is running.

Limitations

Performance

Not great. ADZ is meant to be a good basic shell and easy to mix with golang. But it's not going to beat... probably any other language. Even Tcl itself JIT compiles to byte code and achieves remarkably good performance.

Debugging

The implementation has been purposely kept very simple and naïve, so luxuries like knowing what line an error happened are not available. Really, if you're making a BIG program in ADZ, you're using it wrong.

Documentation

What documentation?

Future Improvements

Namespaces

While this will probably never be incorporated for the MCU version of adz, as it adds too much overhead, for other usecases, having support for namespaces would be very helpful

Packages

Following on namespaces, Packages both go-based and ADZ based would be useful.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrFlowControl          = flowControl("")
	ErrReturn               = flowControl("return")
	ErrBreak                = flowControl("break")
	ErrContinue             = flowControl("continue")
	ErrTailcall             = flowControl("tailcall")
	ErrMaxCallDepthExceeded = flowControl("max call depth exceeded")
)
View Source
var (
	ErrCommandNotFound      = Error(errCommandNotFound)
	ErrSyntax               = Error(errSyntax)
	ErrExpectedMore         = Error(errExpectedMore)
	ErrSyntaxExpected       = Error(errSyntaxExpected)
	ErrEvalCond             = Error(errEvalCond)
	ErrEvalBody             = Error(errEvalBody)
	ErrCondNotBool          = Error(errCondNotBool)
	ErrNoVar                = Error(errNoVar)
	ErrNoNamespace          = Error(errNoNamespace)
	ErrArgCount             = Error(errArgCount)
	ErrArgMinimum           = Error(errArgMinimum)
	ErrArgMissing           = Error(errArgMissing)
	ErrArgExtra             = Error(errArgExtra)
	ErrExpectedArgType      = Error(errExpectedArgType)
	ErrExpectedBool         = Error(errExpectedBool)
	ErrExpectedInt          = Error(errExpectedInt)
	ErrExpectedList         = Error(errExpectedList)
	ErrNamedArgMissingValue = Error(errNamedArgMissingValue)
	ErrCommand              = Error(errCommand)
	ErrLine                 = Error(errLine)
	ErrNotImplemented       = Error(errNotImplemented)
	ErrGoPanic              = Error(errGoPanic)
)
View Source
var (
	EmptyToken = &Token{}
	EmptyList  = List{}
)
View Source
var (
	TrueToken  = &Token{String: "true", Data: true}
	FalseToken = &Token{String: "false", Data: false}
)
View Source
var ListLib = map[string]Proc{}
View Source
var StdLib = make(map[string]Proc)
View Source
var StringsProcs = map[string]Proc{
	"format":       ProcStringsFormat,
	"contains":     ProcStringsContains,
	"containsany":  ProcStringsContainsAny,
	"containsrune": ProcStringsContainsRune,
	"equalfold":    ProcStringsEqualFold,
	"hasprefix":    ProcStringsHasPrefix,
	"hassuffix":    ProcStringsHasSuffix,
	"count":        ProcStringsCount,
	"index":        ProcStringsIndex,
	"lastindex":    ProcStringsLastIndex,
	"indexany":     ProcStringsIndexAny,
	"lastindexany": ProcStringsLastIndexAny,
	"indexrune":    ProcStringsIndexRune,
	"split":        ProcStringsSplit,
	"splitn":       ProcStringsSplitN,
	"splitafter":   ProcStringsSplitAfter,
	"splitaftern":  ProcStringsSplitAfterN,
	"join":         ProcStringsJoin,
	"replace":      ProcStringsReplace,
	"replaceall":   ProcStringsReplaceAll,
	"repeat":       ProcStringsRepeat,
	"tolower":      ProcStringsToLower,
	"toupper":      ProcStringsToUpper,
	"totitle":      ProcStringsToTitle,
	"trim":         ProcStringsTrim,
	"trimleft":     ProcStringsTrimLeft,
	"trimright":    ProcStringsTrimRight,
	"trimspace":    ProcStringsTrimSpace,
	"trimprefix":   ProcStringsTrimPrefix,
	"trimsuffix":   ProcStringsTrimSuffix,
	"compare":      ProcStringsCompare,
	"map":          ProcStringsMap,
	"fields":       ProcStringsFields,
	"fieldsfunc":   ProcStringsFieldsFunc,
}
View Source
var WrapDecider = func(t reflect.Type, v reflect.Value) bool {

	if !v.IsValid() {
		return false
	}

	tokenT := reflect.TypeOf((*Token)(nil)).Elem()
	if t == tokenT || t == reflect.PointerTo(tokenT) {
		return false
	}

	base := t
	for base.Kind() == reflect.Pointer {
		base = base.Elem()
	}

	switch base.Kind() {
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64,
		reflect.String:
		return false
	}

	if hasExportedMethod(v) {
		return true
	}
	if v.CanAddr() && hasExportedMethod(v.Addr()) {
		return true
	}

	return false
}

WrapDecider lets callers override auto-wrap behavior. Return true to wrap, false to leave as a plain NewToken.

Functions

func Flags

func Flags(arg ...*Argument) map[string]*Argument

func JoinErr

func JoinErr(a, b error) error

func LoadStringsProcs

func LoadStringsProcs(interp *Interp)

Optional: convenience loader

func ParseArgsLazy

func ParseArgsLazy(namedProto []*Token, posProto []*Token, args []*Token) (parsedArgs map[string]*Token, err error)

func ParseProto

func ParseProto(proto *Token) (namedProto []*Token, posProto []*Token, err error)

ParseProto parses a proc argument prototype, returning the list of named args and the list of positional args.

func TestNamespaceTokenization_ExtremeNames

func TestNamespaceTokenization_ExtremeNames(t *testing.T)

func TestNamespace_IntrospectionFlatNested

func TestNamespace_IntrospectionFlatNested(t *testing.T)

func TestPlanes_NoCollisions

func TestPlanes_NoCollisions(t *testing.T)

func TokenJoin

func TokenJoin(toks []*Token, joinStr string) string

TokenJoin joins together tokens Return string or return token??

Types

type ArgGroup

type ArgGroup struct {
	Named                      map[string]*Argument
	Pos                        []*Argument
	PosVariadic, NamedVariadic bool
}

func NewArgGroup

func NewArgGroup(args ...*Argument) *ArgGroup

func (*ArgGroup) Arity

func (ag *ArgGroup) Arity() Arity

func (*ArgGroup) GetNamed

func (ag *ArgGroup) GetNamed(name string) *Argument

func (*ArgGroup) Names

func (ag *ArgGroup) Names() (acc []string)

func (*ArgGroup) Prototype

func (ag *ArgGroup) Prototype() string

Prototype shows the prototype for the ArgGroup

type ArgSet

type ArgSet struct {
	Cmd, Help string
	ArgGroups []*ArgGroup
	Lazy      bool
}

func NewArgSet

func NewArgSet(name string, args ...*Argument) *ArgSet

NewArgSet returns an ArgSet with Cmd initialzed with name. If args are supplied, they are added to an ArgGroup and the the ArgGroup is added to ArgSet.

func (*ArgSet) ArgGroup

func (as *ArgSet) ArgGroup(ags ...*ArgGroup)

ArgGroup appends ag to ArgSet's ArgGroups

func (*ArgSet) Arities

func (as *ArgSet) Arities() (arr []Arity)

Return a slice of accepted arities. Not needed any more?

func (*ArgSet) BindArgs

func (as *ArgSet) BindArgs(interp *Interp, args []*Token) (boundArgs map[string]*Token, err error)

BindArgs uses the defined ArgSet to bind arguments passed in args to a map[string]*Token. This map[string]*Token is suitable for passing to interp.Push() as done when invoking a Proc.

func (*ArgSet) BindPosOnly

func (as *ArgSet) BindPosOnly(interp *Interp, args []*Token) (boundArgs map[string]*Token, err error)

BindPosOnly works the same as BindArgs, but it acts as though the first argument after the assumed command is "--" so all args are treated as positional arguments.

func (*ArgSet) GetArgGroup

func (as *ArgSet) GetArgGroup(arr Arity) *ArgGroup

func (*ArgSet) HelpText

func (as *ArgSet) HelpText() string

HelpText generates the entire help message

func (*ArgSet) ParseProto

func (as *ArgSet) ParseProto(proto *Token) error

ParseProto parses a proc prototype (an *adz.Token) into an ArgSet. PasreProto is for generating an ArgSet from a prototype passed from adz. Procs written in go should just build out ArgSet within go.

func (*ArgSet) ShowUsage

func (as *ArgSet) ShowUsage(w io.Writer)

ShowUsage is a convenience for writing the full HelpText to w.

func (*ArgSet) Signature

func (as *ArgSet) Signature() string

Signature generates the command along with the arg prototype

func (*ArgSet) Validate

func (as *ArgSet) Validate() error

Validate makes sure the ArgSet is sane: that Arguments arities are all correct, that it is either PosVariadic or multi-arity or neither.

type Argument

type Argument struct {
	Name    string
	Default *Token
	Coerce  *Token
	Help    string
}

func Arg

func Arg(name string) *Argument

func ArgDefault

func ArgDefault(name string, def *Token) *Argument

func ArgDefaultCoerce

func ArgDefaultCoerce(name string, def, coerce *Token) *Argument

func ArgDefaultHelp

func ArgDefaultHelp(name string, def *Token, help string) *Argument

func ArgHelp

func ArgHelp(name, help string) *Argument

func ParseProtoArg

func ParseProtoArg(arg *Token) (parg *Argument, err error)

func (*Argument) Get

func (arg *Argument) Get(interp *Interp, tok *Token) (ret *Token, err error)

func (*Argument) HelpLine

func (arg *Argument) HelpLine() string

HelpLine returns the argument name, and if it exists, its help text, default value and coerce.

func (*Argument) String

func (arg *Argument) String() string

type Arity

type Arity int

type Command

type Command = List

Command is just a list of tokens.

func (Command) Summary

func (cmd Command) Summary() string

type Deleter

type Deleter interface {
	Del(*Token) (*Token, error)
}

Deleter works slightly differently it is not called in place of the regular delete function, but call first and then the regular delete is performed.

type Equivalence

type Equivalence interface {
	Equal(any) bool
}

type Error

type Error func(...any) error

func (Error) Error

func (e Error) Error() string

func (Error) Is

func (e Error) Is(target error) bool

type Errors

type Errors []error

func (*Errors) Append

func (e *Errors) Append(err error)

func (Errors) Error

func (e Errors) Error() string

type Float

type Float float64

Float and it's single method Float() is a helper to easily pass float64s to things expecting a Floater interface.

func (Float) Float

func (f Float) Float() float64

type Floater

type Floater interface {
	Float() float64
}

Floater is an interface so an otherwise opaque object can signal it is a a float value.

type Frame

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

func (*Frame) Namespace

func (f *Frame) Namespace() string

type Getter

type Getter interface {
	Get(src *Token) (*Token, error)
}

Getter hooks getting a variable. If the token's .Data field implements Getter, Get() is called in lieu of returning varMap["name"]. src is the token that owns the .Data field.

type Integer

type Integer interface {
	Int() int
}

type Interfacer

type Interfacer interface {
	Interface() any
}

Interfacer is an interface that allows a Token to be overloaded with type infomation. For example, if a third party object is wrapped so that it can implement Getter/Setter/TokenMarshler etc, but still want to be able to retrieve and pass the wrapped value around, have the object implement Interfacer.

type ExternalType struct {}

type WrappedType struct {
	ExternalType
}

func(wt *WrappedType) Interfacer() any {
  return wt.ExternalType
}

type Interp

type Interp struct {
	Stdin      io.Reader
	Stdout     io.Writer
	Stderr     io.Writer
	Namespaces map[string]*Namespace
	Stack      []*Frame
	Frame      *Frame
	Monotonic  Monotonic

	MaxCallDepth int

	*sync.Mutex
	// contains filtered or unexported fields
}

func NewInterp

func NewInterp() *Interp

func (*Interp) AbsoluteProc

func (interp *Interp) AbsoluteProc(qualPath string) Proc

AbsoluteProc exclusively takes a fully qualified path and returns the matching proc if found. Otherwise it returns nil.

func (*Interp) CallDepth

func (interp *Interp) CallDepth() int

func (*Interp) DelVar

func (interp *Interp) DelVar(name string) (*Token, error)

func (*Interp) Exec

func (interp *Interp) Exec(cmd Command) (tok *Token, err error)

func (*Interp) ExecBytes

func (interp *Interp) ExecBytes(rawScript []byte) (*Token, error)

func (*Interp) ExecLiteral

func (interp *Interp) ExecLiteral(cmd Command) (tok *Token, err error)

ExecLiteral executes cmd without first doing a substitution pass.

func (*Interp) ExecScript

func (interp *Interp) ExecScript(script Script) (ret *Token, err error)

func (*Interp) ExecString

func (interp *Interp) ExecString(str string) (*Token, error)

func (*Interp) ExecToken

func (interp *Interp) ExecToken(tok *Token) (*Token, error)

func (*Interp) GetVar

func (interp *Interp) GetVar(name string) (v *Token, err error)

func (*Interp) LoadProcs

func (interp *Interp) LoadProcs(ns string, procset map[string]Proc)

func (*Interp) Pop

func (interp *Interp) Pop()

func (*Interp) Printf

func (interp *Interp) Printf(format string, args ...any)

func (*Interp) Proc

func (interp *Interp) Proc(name string, proc Proc) (err error)

func (*Interp) Push

func (interp *Interp) Push(frame *Frame)

func (*Interp) ResolveIdentifier

func (interp *Interp) ResolveIdentifier(id string, create bool) (*Namespace, string, error)

func (*Interp) ResolveProc

func (interp *Interp) ResolveProc(name string) (Proc, error)

func (*Interp) SetVar

func (interp *Interp) SetVar(name string, val *Token) (*Token, error)

func (*Interp) Subst

func (interp *Interp) Subst(tok *Token) (*Token, error)

type List

type List []*Token

func LexBytesToList

func LexBytesToList(buf []byte) (List, error)

func ListOfLists

func ListOfLists(list List, separator string) (lol []List)

not sure if this is useful anywhere else... just leave it here for now

func (List) Len

func (l List) Len() int

func (List) Less

func (l List) Less(i, j int) bool

func (List) Proc

func (l List) Proc(interp *Interp, args []*Token) (*Token, error)

func (List) Swap

func (l List) Swap(i, j int)

type Map

type Map map[string]*Token

type Monotonic

type Monotonic map[string]uint

func (Monotonic) Next

func (m Monotonic) Next(prefix string) string

type Namespace

type Namespace struct {
	Name  string
	Vars  map[string]*Token
	Procs map[string]Proc
}

func NewNamespace

func NewNamespace(name string) *Namespace

func (*Namespace) Qualified

func (ns *Namespace) Qualified(id string) string

Qualified takes id and returns a fully qualified identifier

type NilReader

type NilReader struct{}

func (*NilReader) Read

func (nr *NilReader) Read([]byte) (n int, err error)

should always return 0, EOF instead of 0, nil ?

type Number

type Number interface {
	constraints.Integer | constraints.Float
}

type PlaneCase

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

type Proc

type Proc func(*Interp, []*Token) (*Token, error)

func (Proc) AsToken

func (proc Proc) AsToken(str string) *Token

func (Proc) Proc

func (proc Proc) Proc(interp *Interp, args []*Token) (*Token, error)

Proc proc? proc! Proc proc proc.

type Procer

type Procer interface {
	Proc(*Interp, []*Token) (*Token, error)
}

Procer (would you pronounce that like "procker" or "pro-sir"?) is an interface that allows an object, especially one referenced by the Data field of a token, to be callable as a Proc; the differs from storing a Proc in the Data field of token, such that it can implement other interfaces as well.

type Ref

type Ref struct {
	Name      string
	Frame     *Frame
	Namespace *Namespace
}

Ref is a Getter, Setter, and Deleter that implements cross-frame and cross-namespace references, and is used by ProcImport.

func (*Ref) Del

func (r *Ref) Del(*Token) (*Token, error)

Del deletes the token that ref points to, but not itself. Unlike Get and Set Calling Del does not override the interpreter's deletion of the variable.

func (*Ref) Get

func (r *Ref) Get(*Token) (*Token, error)

func (*Ref) Set

func (r *Ref) Set(self, val *Token) (*Token, error)

func (*Ref) Token

func (r *Ref) Token() *Token

Token generates a token with it's .Data set to the ref

type Runable

type Runable interface {
	Exec() (*Token, error)
}

type Script

type Script []Command

Script is a set of a commands and a set of commands are a set of tokens

func LexBytes

func LexBytes(buf []byte) (Script, error)

func LexString

func LexString(str string) (Script, error)

type Setter

type Setter interface {
	Set(src *Token, val *Token) (*Token, error)
}

Setter hooks setting a variable. If the token's .Data field implements Setter, Set() is called in lieu of setting varMap["name"]. src is the token with the .Data field that implements Setter. val is the token that was passed to set command. Typically set returns the value it was set to, but the Setter interface allows you to diverge from this behavior.

type Signal

type Signal int

Signals are akin to unix signals (but not the same thing!) Interpreters will keep running until they run out of commands or if they get a signal. Signals are implemented via go channels.

const (
	SignalRun Signal = iota
	SignalBreak
	SignalStop
	SignalAbort
	SignalKill
)

func (Signal) Signal

func (sig Signal) Signal()

func (Signal) String

func (sig Signal) String() string

type Token

type Token struct {
	String string
	Data   any
}

func LexStringToList

func LexStringToList(str string) ([]*Token, error)

func NewList

func NewList(s []*Token) *Token

func NewToken

func NewToken(v any) *Token

func NewTokenBytes

func NewTokenBytes(str []byte) *Token

func NewTokenCat

func NewTokenCat(toks ...*Token) *Token

NewTokenCat makes a new token by concatenating the supplied tokens together

func NewTokenInt

func NewTokenInt(i int) *Token

func NewTokenListString

func NewTokenListString(strs []string) (list []*Token)

func NewTokenString

func NewTokenString(str string) *Token

func ParseArgs

func ParseArgs(args []*Token) (namedArgs map[string]*Token, posArgs []*Token, err error)

ParseArgs takes a slice of adz *Tokens and parses them per this rule set:

  • The first argument is skipped; this is assumed to be the command.
  • An argument starting with a dash is a named argument.
  • The token after a named arguement is the value.
  • It is an error to have a named argument without a following value argument.
  • If the argument does not start with a dash, it is a positional argument.
  • After an argument of -- is passed, all subsequent arguments including those that start with a dash will be treated as positional arguments.
  • Single or zero character arguments are always positional.

func ProcAnd

func ProcAnd(interp *Interp, args []*Token) (*Token, error)

func ProcBool

func ProcBool(interp *Interp, args []*Token) (*Token, error)

func ProcBreak

func ProcBreak(interp *Interp, args []*Token) (*Token, error)

func ProcCatch

func ProcCatch(interp *Interp, args []*Token) (*Token, error)

ProcCatch

func ProcConcat

func ProcConcat(interp *Interp, args []*Token) (*Token, error)

ProcConcat returns its arguments concatenated

func ProcContinue

func ProcContinue(interp *Interp, args []*Token) (*Token, error)

func ProcDel

func ProcDel(interp *Interp, args []*Token) (*Token, error)

func ProcDiff

func ProcDiff(interp *Interp, args []*Token) (*Token, error)

ProcDiff

func ProcDiv

func ProcDiv(interp *Interp, args []*Token) (*Token, error)

ProcDiv

func ProcDoWhile

func ProcDoWhile(interp *Interp, args []*Token) (*Token, error)

ProcDoWhile

func ProcEq

func ProcEq(interp *Interp, args []*Token) (*Token, error)

ProcEq performs a shallow comparison

func ProcEval

func ProcEval(interp *Interp, args []*Token) (*Token, error)

func ProcFalse

func ProcFalse(interp *Interp, args []*Token) (*Token, error)

func ProcFloat

func ProcFloat(interp *Interp, args []*Token) (*Token, error)

func ProcFor

func ProcFor(interp *Interp, args []*Token) (*Token, error)

ProcFor for {initial} {cond} {step} {body}

func ProcForEach

func ProcForEach(interp *Interp, args []*Token) (ret *Token, err error)

ProcForEach

func ProcGoType

func ProcGoType(interp *Interp, args []*Token) (*Token, error)

ProcGoType implements gotype, a coercer proc that ensures the underlying type of Data is the the go type specified. gotype *gopackage.SomeType $token

func ProcIdx

func ProcIdx(interp *Interp, args []*Token) (*Token, error)

func ProcIf

func ProcIf(interp *Interp, args []*Token) (*Token, error)

func ProcImport

func ProcImport(interp *Interp, args []*Token) (*Token, error)

ProcImport implements the import proc. With one arg, import climbs the stack, looking for a variable with the same name and puts it into the localvars. With two vars, the first must be a fully qualified name. This var is linked as the

Globs only for fully qualified identifiers. import -proc ::list::* ;# import all procs in ::list namespace import ::ns::* ;# import all variables from ::ns name space

combined:

import -proc {::list::idx ::list::someVar} -proc ::list::len import -proc {::list::idx ::list::len}

func ProcIncr

func ProcIncr(interp *Interp, args []*Token) (*Token, error)

ProcIncr

func ProcInt

func ProcInt(interp *Interp, args []*Token) (*Token, error)

func ProcLen

func ProcLen(interp *Interp, args []*Token) (*Token, error)

func ProcList

func ProcList(interp *Interp, args []*Token) (*Token, error)

ProcList returns a well-formed list. The list is pre-parsed as a list and will be readily accessible for use as a list.

func ProcListAppend

func ProcListAppend(interp *Interp, args []*Token) (*Token, error)

func ProcListContains

func ProcListContains(interp *Interp, args []*Token) (*Token, error)

func ProcListFind

func ProcListFind(interp *Interp, args []*Token) (*Token, error)

func ProcListMap

func ProcListMap(interp *Interp, args []*Token) (*Token, error)

func ProcListReverse

func ProcListReverse(interp *Interp, args []*Token) (*Token, error)

func ProcListSet

func ProcListSet(interp *Interp, args []*Token) (*Token, error)

func ProcListSplit

func ProcListSplit(interp *Interp, args []*Token) (*Token, error)

TODO: split on multiple substrs. TODO: Check args

func ProcListUniq

func ProcListUniq(interp *Interp, args []*Token) (*Token, error)

func ProcMacro

func ProcMacro(interp *Interp, args []*Token) (*Token, error)

do we want to have macros support arguments? if we do that then it's perhaps too similar to a proc? It's just a proc that doesn't isolate its vars

func ProcMul

func ProcMul(interp *Interp, args []*Token) (*Token, error)

ProcMul

func ProcNamespace

func ProcNamespace(interp *Interp, args []*Token) (*Token, error)

Namespace

func ProcNeq

func ProcNeq(interp *Interp, args []*Token) (*Token, error)

ProcNeq performs a shallow comparison

func ProcNot

func ProcNot(interp *Interp, args []*Token) (*Token, error)

ProcNot performs a boolean not

func ProcOr

func ProcOr(interp *Interp, args []*Token) (*Token, error)

func ProcPipeline

func ProcPipeline(interp *Interp, args []*Token) (*Token, error)

With 1 argument, chain executes it as a script. After each command in the script, the output of the command is saved into the special variable $|. This can then be used in the next command as input. With two arguments the final output of the chain is stored in a variable of that name.

Example:

	pipeline result {
		curl wobpage.net/data
		lindex $| 0
		field $| key.value.*
		touch $|
 }

func ProcPrint

func ProcPrint(interp *Interp, args []*Token) (*Token, error)

func ProcProc

func ProcProc(interp *Interp, args []*Token) (*Token, error)

func ProcReturn

func ProcReturn(interp *Interp, args []*Token) (*Token, error)

func ProcSet

func ProcSet(interp *Interp, args []*Token) (*Token, error)

func ProcSlice

func ProcSlice(interp *Interp, args []*Token) (*Token, error)

func ProcSort

func ProcSort(interp *Interp, args []*Token) (*Token, error)

TODO: add various options like -type <numeric> and -order <reverse>

func ProcStringsCompare

func ProcStringsCompare(interp *Interp, args []*Token) (*Token, error)

func ProcStringsContains

func ProcStringsContains(interp *Interp, args []*Token) (*Token, error)

func ProcStringsContainsAny

func ProcStringsContainsAny(interp *Interp, args []*Token) (*Token, error)

func ProcStringsContainsRune

func ProcStringsContainsRune(interp *Interp, args []*Token) (*Token, error)

func ProcStringsCount

func ProcStringsCount(interp *Interp, args []*Token) (*Token, error)

func ProcStringsEqualFold

func ProcStringsEqualFold(interp *Interp, args []*Token) (*Token, error)

func ProcStringsFields

func ProcStringsFields(interp *Interp, args []*Token) (*Token, error)

strings.Fields: split on runs of space (no callback needed)

func ProcStringsFieldsFunc

func ProcStringsFieldsFunc(interp *Interp, args []*Token) (*Token, error)

strings.FieldsFunc: predicate proc gets one rune; truthy => split

func ProcStringsFormat

func ProcStringsFormat(interp *Interp, args []*Token) (*Token, error)

func ProcStringsHasPrefix

func ProcStringsHasPrefix(interp *Interp, args []*Token) (*Token, error)

func ProcStringsHasSuffix

func ProcStringsHasSuffix(interp *Interp, args []*Token) (*Token, error)

func ProcStringsIndex

func ProcStringsIndex(interp *Interp, args []*Token) (*Token, error)

func ProcStringsIndexAny

func ProcStringsIndexAny(interp *Interp, args []*Token) (*Token, error)

func ProcStringsIndexRune

func ProcStringsIndexRune(interp *Interp, args []*Token) (*Token, error)

func ProcStringsJoin

func ProcStringsJoin(interp *Interp, args []*Token) (*Token, error)

func ProcStringsLastIndex

func ProcStringsLastIndex(interp *Interp, args []*Token) (*Token, error)

func ProcStringsLastIndexAny

func ProcStringsLastIndexAny(interp *Interp, args []*Token) (*Token, error)

func ProcStringsMap

func ProcStringsMap(interp *Interp, args []*Token) (*Token, error)

strings.Map: map each rune via a proc: mapper :: r -> string (or empty to drop)

func ProcStringsRepeat

func ProcStringsRepeat(interp *Interp, args []*Token) (*Token, error)

func ProcStringsReplace

func ProcStringsReplace(interp *Interp, args []*Token) (*Token, error)

func ProcStringsReplaceAll

func ProcStringsReplaceAll(interp *Interp, args []*Token) (*Token, error)

func ProcStringsSplit

func ProcStringsSplit(interp *Interp, args []*Token) (*Token, error)

func ProcStringsSplitAfter

func ProcStringsSplitAfter(interp *Interp, args []*Token) (*Token, error)

func ProcStringsSplitAfterN

func ProcStringsSplitAfterN(interp *Interp, args []*Token) (*Token, error)

func ProcStringsSplitN

func ProcStringsSplitN(interp *Interp, args []*Token) (*Token, error)

func ProcStringsToLower

func ProcStringsToLower(interp *Interp, args []*Token) (*Token, error)

func ProcStringsToTitle

func ProcStringsToTitle(interp *Interp, args []*Token) (*Token, error)

func ProcStringsToUpper

func ProcStringsToUpper(interp *Interp, args []*Token) (*Token, error)

func ProcStringsTrim

func ProcStringsTrim(interp *Interp, args []*Token) (*Token, error)

func ProcStringsTrimLeft

func ProcStringsTrimLeft(interp *Interp, args []*Token) (*Token, error)

func ProcStringsTrimPrefix

func ProcStringsTrimPrefix(interp *Interp, args []*Token) (*Token, error)

func ProcStringsTrimRight

func ProcStringsTrimRight(interp *Interp, args []*Token) (*Token, error)

func ProcStringsTrimSpace

func ProcStringsTrimSpace(interp *Interp, args []*Token) (*Token, error)

func ProcStringsTrimSuffix

func ProcStringsTrimSuffix(interp *Interp, args []*Token) (*Token, error)

func ProcSubst

func ProcSubst(interp *Interp, args []*Token) (*Token, error)

func ProcSum

func ProcSum(interp *Interp, args []*Token) (*Token, error)

ProcSum

func ProcTailcall

func ProcTailcall(interp *Interp, args []*Token) (*Token, error)

func ProcThrow

func ProcThrow(interp *Interp, args []*Token) (*Token, error)

ProcThrow

func ProcTrue

func ProcTrue(interp *Interp, args []*Token) (*Token, error)

func ProcTuple

func ProcTuple(interp *Interp, args []*Token) (*Token, error)

func ProcUnicodeIsLetter

func ProcUnicodeIsLetter(interp *Interp, args []*Token) (*Token, error)

Bonus: quick Unicode helpers if you want them exposed too

func ProcVar

func ProcVar(interp *Interp, args []*Token) (*Token, error)

var varname - returns true/false if varname exists or doesn't exist var varname {val} sets varname to val var varname cmd <args> does a variable subcommand like... var varname idx n ;# treat varname as a list and return the nth index of varname; var varname idx {n1 n2 n3...} ;# treat varname as a list and return the n3-th index of the n2-th index of the n1-th index of varname; var varname idx n val;# treat varname as a list and set the nth index of varname to val var varname len ;# treat varname as a list and return its length var varname append ;# append

func ProcWhile

func ProcWhile(interp *Interp, args []*Token) (*Token, error)

func Wrap

func Wrap(v any) *Token

Wrap takes any value v and returns a *Token that prints like v and is invocable as a Proc: [$obj <Method> arg ...]. Method is validated via ArgSet using a tuple coercer that lists all valid methods.

func (*Token) Append

func (tok *Token) Append(elements ...*Token) *Token

this might break my "variables are immutable" goal

func (*Token) AsBool

func (tok *Token) AsBool() (bool, error)

func (*Token) AsCommand

func (tok *Token) AsCommand() (Command, error)

AsCommand is similar to AsList, but doesn't overwrite the underlaying Data type so anonymous procs are preserved.

func (*Token) AsFloat

func (tok *Token) AsFloat() (float64, error)

func (*Token) AsInt

func (tok *Token) AsInt() (int, error)

func (*Token) AsList

func (tok *Token) AsList() (list []*Token, err error)

func (*Token) AsMap

func (tok *Token) AsMap() (Map, error)

func (*Token) AsProc

func (tok *Token) AsProc(interp *Interp) (Proc, error)

func (*Token) AsScript

func (tok *Token) AsScript() (Script, error)

func (*Token) AsTuple

func (tok *Token) AsTuple(list []*Token) (*Token, error)

AsTuple ensures that tok is equal to one of the values in list or an error is thrown.

func (*Token) Equal

func (tok *Token) Equal(c *Token) bool

func (*Token) Error

func (tok *Token) Error() string

Make Token implement error... Hmmm

func (*Token) Index

func (tok *Token) Index(idx int) *Token

Index treats tok as a list and returns the idx'th element of tok. A negative index is treated as backwards (so -1 is the last element). Non existent elements return an EmptyToken.

func (*Token) IndexSet

func (tok *Token) IndexSet(idx int, value *Token) (*Token, error)

func (*Token) IsTrue

func (tok *Token) IsTrue() bool

func (*Token) Len

func (tok *Token) Len() int

Len treats tok as a list and returns the number of elements in the list.

func (*Token) ListOfOne

func (tok *Token) ListOfOne() bool

ListOfOne returns true when interpreting token as a List, it has a Length of 1 or zero.

func (*Token) Literal

func (tok *Token) Literal() string

Literal is the converse of Quoted. It returns the token string stripped of any quoting brackets.

func (*Token) Quoted

func (tok *Token) Quoted() string

Quoted returns the string form of the token quoted (with {}) if needed. This only applies to backslashes and spaces TODO: add in data.(type) checks and rigorously quote?

func (*Token) Slice

func (tok *Token) Slice(start, end int) *Token

func (*Token) Summary

func (tok *Token) Summary() string

Summary returns a string, sumarized with the middle bit elided

type TokenMarshaler

type TokenMarshaler interface {
	MarshalToken() (*Token, error)
}

type TokenUnmarshaler

type TokenUnmarshaler interface {
	UnmarshalToken(*Token) error
}

type UsageError

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

func (*UsageError) Error

func (ue *UsageError) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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