123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- package attl
- type Attl struct {
- index int
- input string
- }
- type Proc func(*Environment, ...Value) (Value, Effect)
- func (pv Proc) String() string {
- return "proc"
- }
- // Evaler is an interface to a Value that can evaluate itself
- // based on and possibly modifying a given environment.
- type Evaler interface {
- Eval(*Environment, ...Value) (Value, Effect)
- }
- // Lazyer is an interface to a Value that does not automatically
- // evaluate itself in List and similar contexts.
- type Lazyer interface {
- // Lazy is a marker method only.
- Lazy()
- }
- // Value is an interface for the basic unit of data that
- // the ATTL interpreter works with.
- // It is used both for run time data and parsing data.
- type Value interface {
- // Since ATTL is TCL-like, all values must be
- // convertable to string
- String() string
- // Furthermore any ATTL value must be able to evaluate itself.
- Evaler
- }
- // Typer is an interface that Values can optionally implement to
- // allow them to report their type.
- type Typer interface {
- Type() Type
- }
- type Int int
- type Bool bool
- type String string
- type Word string
- type Type string
- type Comment string
- type Error struct {
- Message string
- Index int
- Children List
- }
- type List []Value
- type Map map[string]Value
- func (m Map) Keys() List {
- res := List{}
- for k, _ := range m {
- res = append(res, String(k))
- }
- return res
- }
- func (m Map) SortedKeys() List {
- return m.Keys().SortStrings()
- }
- type Getter struct {
- Key Value
- }
- type Evaluation struct {
- Command
- }
- type Command struct {
- Order Value
- Parameters List
- }
- type Block struct {
- Statements List
- }
- type Defined struct {
- Name string
- Params List
- Block
- }
- type Wrapper struct {
- Kind Type
- Handle interface{}
- Methods Map
- }
- type Object struct {
- Wrapper
- Fields Map
- Embedded Map
- }
- type Overload Map
- func (bv Bool) String() string {
- if bv {
- return "true"
- }
- return "false"
- }
- func (sv String) String() string {
- return string(sv)
- }
- func (cv Comment) String() string {
- return string(cv)
- }
- func (sv Word) String() string {
- return string(sv)
- }
- func (tv Type) String() string {
- return string(tv)
- }
- func (gv Getter) String() string {
- return gv.Key.String()
- }
- func (cv Command) String() string {
- return cv.Order.String() + " " + cv.Parameters.String()
- }
- func (gv Evaluation) String() string {
- return gv.Command.String()
- }
- func (bv Block) String() string {
- return "{" + bv.Statements.String() + "}"
- }
- func (dv Defined) String() string {
- return "to " + dv.Name + " (" +
- dv.Params.String() + ") " + dv.Block.String()
- }
- func (cv Overload) String() string {
- return Map(cv).String()
- }
- // Lazy marks that Blocks should be lazily evaluated.
- func (Block) Lazy() {}
- func (iv Int) String() string {
- return Itoa(int(iv))
- }
- func (lv Map) String() string {
- aid := "[map "
- for k, v := range lv {
- aid += " "
- aid += k
- aid += " "
- aid += v.String()
- }
- aid += "]"
- return aid
- }
- func (lv List) String() string {
- aid := "[list"
- for _, v := range lv {
- aid += " "
- if v == nil {
- aid += "nil"
- } else {
- aid += v.String()
- }
- }
- aid += "]"
- return aid
- }
- func (ev Error) String() string {
- return string(ev.Message)
- }
- func (ev Error) Error() string {
- return ev.Message
- }
- // Implement the effect interface
- func (ev *Error) Flow() Flow {
- if ev == nil {
- return NormalFlow
- }
- return FailFlow
- }
- func (ev *Error) Unwrap() Value {
- if ev == nil {
- return nil
- }
- return ev
- }
- func NewError(message string, index int, children ...Value) *Error {
- return &Error{message, index, children}
- }
- func ErrorFromString(message string) *Error {
- return NewError(message, -1)
- }
- func ErrorFromError(err error, children ...Value) *Error {
- if err == nil {
- return nil
- }
- return NewError(err.Error(), -1, children...)
- }
- // Break is used for break flows
- type Break struct {
- Value // value returned by break
- }
- func (bv Break) Flow() Flow {
- return BreakFlow
- }
- func (bv Break) Unwrap() Value {
- return bv.Value
- }
- // Return is used for return flows
- type Return struct {
- Value // value returned
- }
- func (rv Return) Flow() Flow {
- return ReturnFlow
- }
- func (bv Return) Unwrap() Value {
- return bv.Value
- }
- // Rescue is used to evaluate rescue commands
- type Rescue struct {
- Block // A rescue is a special block
- }
- // Rescue essentially protects the block from
- // rescue recursion by pushing the stack once.
- func (r Rescue) Eval(env *Environment, args ...Value) (Value, Effect) {
- // ignore the stack depth
- // protection here to be sure the
- // rescue block is executed
- _ = env.Push()
- env.Rescuing = true
- env.Printi("Rescuing.\n")
- defer env.Pop()
- defer func() {
- env.Rescuing = false
- }()
- return r.Block.Eval(env, args...)
- }
- func (iv Wrapper) String() string {
- aid := "[interface"
- aid += " " + iv.Kind.String()
- aid += " " + iv.Methods.String()
- aid += "]"
- return aid
- }
- func (sv Object) String() string {
- aid := "[struct"
- aid += " " + sv.Kind.String()
- aid += " " + sv.Methods.String()
- aid += " " + sv.Fields.String()
- aid += " " + sv.Embedded.String()
- aid += "]"
- return aid
- }
- func NewAttl(input string) Attl {
- return Attl{0, input}
- }
- func (wv Word) Eval(env *Environment, args ...Value) (Value, Effect) {
- return wv, nil
- }
- func (sv String) Eval(env *Environment, args ...Value) (Value, Effect) {
- return sv, nil
- }
- func (tv Type) Eval(env *Environment, args ...Value) (Value, Effect) {
- return tv, nil
- }
- func (iv Int) Eval(env *Environment, args ...Value) (Value, Effect) {
- return iv, nil
- }
- func (bv Bool) Eval(env *Environment, args ...Value) (Value, Effect) {
- return bv, nil
- }
- func (ev Error) Eval(env *Environment, args ...Value) (Value, Effect) {
- return ev, nil
- }
- // Eval of a List expands arguments, except Lazyer elements.
- func (lv List) Eval(env *Environment, args ...Value) (Value, Effect) {
- res := List{}
- for _, s := range lv {
- _, isLazy := s.(Lazyer)
- if isLazy {
- res = append(res, s)
- } else {
- val, err := s.Eval(env, args...)
- if err != nil {
- return val, err
- }
- res = append(res, val)
- }
- }
- return res, nil
- }
- func (mv Map) Eval(env *Environment, args ...Value) (Value, Effect) {
- return mv, nil
- }
- func (cv Comment) Eval(env *Environment, args ...Value) (Value, Effect) {
- return nil, nil
- }
- func (bv Block) Eval(env *Environment, args ...Value) (Value, Effect) {
- var res Value
- var eff Effect
- // set parameters to $1 ... $(len(args))
- for i, a := range args {
- name := Itoa(i + 1)
- env.Define(name, a, 0)
- }
- // Set $argc to amount of arguments
- // and $argv to arguments as well
- env.Define("argc", Int(len(args)), 0)
- env.Define("argv", List(args), 0)
- for _, s := range bv.Statements {
- // Call the statement.
- res, eff = s.Eval(env, args...)
- // if the flow is not normal anymore,
- // end the block execution at this point
- if eff != nil && eff.Flow() > NormalFlow {
- // If it was a break, unwrap and done,
- if eff.Flow() <= BreakFlow {
- return eff.Unwrap(), nil
- } else if eff.Flow() == FailFlow {
- // If it is a fail try to rescue it
- return env.Rescue(res, eff)
- }
- return res, eff
- }
- env.Define("RESULT", res, 0)
- }
- return res, eff
- }
- func (pv Proc) Eval(env *Environment, args ...Value) (Value, Effect) {
- return pv(env, args...)
- }
- func (cv Command) Eval(env *Environment, args ...Value) (Value, Effect) {
- val, eff := cv.Order.Eval(env)
- if eff != nil || val == nil {
- return val, eff
- }
- name := val.String()
- fun := env.Lookup(name)
- if fun == nil {
- return nil, ErrorFromString("Cannot evaluate nil order: " + name)
- }
- eva, ok := fun.(Evaler)
- if !ok {
- return nil, ErrorFromString("Cannot evaluate: " + name)
- }
- err := env.Push()
- // stack depth protection
- if err != nil {
- return env.Rescue(env.Fail(err))
- }
- defer env.Pop()
- fargs := cv.Parameters
- // Expand Evaluation arguments, but not block elements.
- eargs, eff := fargs.Eval(env, args...)
- if eff != nil {
- return nil, eff
- }
- return eva.Eval(env, eargs.(List)...)
- }
- func (gv Getter) Eval(env *Environment, args ...Value) (Value, Effect) {
- val, err := gv.Key.Eval(env)
- if err != nil || val == nil {
- return val, err
- }
- return env.Lookup(val.String()), nil
- }
- func (ev Evaluation) Eval(env *Environment, args ...Value) (Value, Effect) {
- err := env.Push()
- // stack depth protection
- if err != nil {
- return env.Fail(err)
- }
- defer env.Pop()
- val, eff := ev.Command.Eval(env, args...)
- return val, eff
- }
- func (dv Defined) Eval(env *Environment, args ...Value) (Value, Effect) {
- err := env.Push()
- // stack depth protection
- if err != nil {
- return env.Rescue(env.Fail(err))
- }
- if len(dv.Params) > len(args) {
- return env.FailString("Not enough arguments")
- }
- for i := 0; i < len(dv.Params); i++ {
- env.Define(dv.Params[i].String(), args[i], 0)
- }
- // $0 contains the name of the defined procedure
- env.Define("0", String(dv.Name), 0)
- defer env.Pop()
- val, eff := dv.Block.Eval(env, args...)
- if eff == nil || eff.Flow() < ReturnFlow {
- return val, nil
- } else if eff.Flow() == ReturnFlow {
- return eff.Unwrap(), nil
- } else { // failures pass through
- return val, eff
- }
- }
- func (iv Wrapper) Eval(env *Environment, args ...Value) (Value, Effect) {
- // Object like values such as interfaces or structs
- // have methods that are called with the method
- // name as the first word argument, which is used
- // to dispatch the function.
- // The dispathed function receives the object
- // as it's first argument
- var name Word
- err := Args(args, &name)
- if err != nil {
- return env.Fail(err)
- }
- method, ok := iv.Methods[name.String()]
- if !ok {
- return env.FailString("No such method ${1}", name)
- }
- args[0] = iv
- return method.Eval(env, args...)
- }
- func (sv Object) Eval(env *Environment, args ...Value) (Value, Effect) {
- // See interface for this dispatch
- var name Word
- err := Args(args, &name)
- if err != nil {
- return env.Fail(err)
- }
- method, ok := sv.Methods[name.String()]
- if !ok {
- return env.FailString("No such method ${1}", name)
- }
- args[0] = sv
- return method.Eval(env, args...)
- }
- func TypeOf(val Value) Type {
- if typer, ok := val.(Typer); ok {
- return typer.Type()
- } else {
- return Type("Unknown")
- }
- }
- func (cv Overload) Eval(env *Environment, args ...Value) (Value, Effect) {
- signature := ""
- for _, arg := range args {
- signature += "_" + TypeOf(arg).String()
- }
- target, ok := cv[signature]
- if ok {
- return target.Eval(env, args...)
- }
- return env.FailString("No overload defined for signature: " + signature)
- }
- // Implement Typer interface for commonly used Values
- func (String) Type() Type { return Type("String") }
- func (Bool) Type() Type { return Type("Bool") }
- func (Int) Type() Type { return Type("Int") }
- func (Error) Type() Type { return Type("Error") }
- func (List) Type() Type { return Type("List") }
- func (Map) Type() Type { return Type("Map") }
- func (Proc) Type() Type { return Type("Proc") }
- func (Word) Type() Type { return Type("Word") }
- func (Defined) Type() Type { return Type("Defined") }
- func (Block) Type() Type { return Type("Block") }
- func (Command) Type() Type { return Type("Command") }
- func (Getter) Type() Type { return Type("Getter") }
- func (Evaluation) Type() Type { return Type("Evaluation") }
- func (t Type) Type() Type { return Type("Type") }
- func (s Object) Type() Type { return s.Kind }
- func (i Wrapper) Type() Type { return i.Kind }
- func (t Type) Overload() Type { return Type("Overload") }
|