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") }