Skip to content

Commit

Permalink
Merge pull request #189 from ichiban/write-option-variable-names
Browse files Browse the repository at this point in the history
add `variable_names` write-option
  • Loading branch information
ichiban authored Apr 2, 2022
2 parents f609059 + 9830dd2 commit 64903d4
Show file tree
Hide file tree
Showing 8 changed files with 360 additions and 66 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ $(go env GOPATH)/bin/1pl [<file>...]
- `Options` is a list of write options listed below:
- **`quoted(Bool)`** `Bool` is either `true` or `false`. If `true`, atoms and functors will be quoted as needed.
- **`ignore_ops(Bool)`** `Bool` is either `true` or `false`. If `true`, operators will be written in functional notation.
- **`variable_names(VN_list)`** `VN_list` is a proper list which element is a form of `A = V` where `A` is an atom and `V` is a variable. Each occurrence of `V` will be replaced by the leftmost and unquoted `A`.
- **`numbervars(Bool)`** `Bool` is either `true` or `false`. If `true`, terms `'$VAR'(0)`, `'$VAR'(1)`, ... will be written as `A`, `B`, ...
- **`write_term(Term, Options)`** Equivalent to `current_output(S), write_term(S, Term, Options)`. *ISO*
- **`write(S_or_a, Term)`** Equivalent to `write_term(S_or_a, Term, [numbervars(true)])`. *ISO*
Expand Down
2 changes: 1 addition & 1 deletion engine/atom.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (a Atom) Apply(args ...Term) Term {

// Unparse emits tokens that represent the atom.
func (a Atom) Unparse(emit func(Token), _ *Env, opts ...WriteOption) {
wto := defaultWriteTermOptions
wto := defaultWriteOptions
for _, o := range opts {
o(&wto)
}
Expand Down
86 changes: 59 additions & 27 deletions engine/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -1377,47 +1377,79 @@ func (state *State) Write(w io.Writer, t Term, env *Env, opts ...WriteOption) er
}

func writeTermOption(state *State, option Term, env *Env) (WriteOption, error) {
type optionIndicator struct {
functor, arg Atom
}

var oi optionIndicator
switch option := env.Resolve(option).(type) {
switch o := env.Resolve(option).(type) {
case Variable:
return nil, ErrInstantiation
case *Compound:
if len(option.Args) != 1 {
return nil, domainErrorWriteOption(option)
if len(o.Args) != 1 {
return nil, domainErrorWriteOption(o)
}

switch v := env.Resolve(option.Args[0]).(type) {
if o.Functor == "variable_names" {
vns := variableNames(o.Args[0], env)
if vns == nil {
return nil, domainErrorWriteOption(o)
}
return WithVariableNames(vns), nil
}

var b bool
switch v := env.Resolve(o.Args[0]).(type) {
case Variable:
return nil, ErrInstantiation
case Atom:
oi = optionIndicator{functor: option.Functor, arg: v}
switch v {
case "true":
b = true
case "false":
b = false
default:
return nil, domainErrorWriteOption(o)
}
default:
return nil, domainErrorWriteOption(o)
}

switch o.Functor {
case "quoted":
return WithQuoted(b), nil
case "ignore_ops":
return state.WithIgnoreOps(b), nil
case "numbervars":
return WithNumberVars(b), nil
default:
return nil, domainErrorWriteOption(option)
return nil, domainErrorWriteOption(o)
}
default:
return nil, domainErrorWriteOption(option)
return nil, domainErrorWriteOption(o)
}
}

switch oi {
case optionIndicator{functor: "quoted", arg: "true"}:
return WithQuoted(true), nil
case optionIndicator{functor: "quoted", arg: "false"}:
return WithQuoted(false), nil
case optionIndicator{functor: "ignore_ops", arg: "true"}:
return state.WithIgnoreOps(true), nil
case optionIndicator{functor: "ignore_ops", arg: "false"}:
return state.WithIgnoreOps(false), nil
case optionIndicator{functor: "numbervars", arg: "true"}:
return WithNumberVars(true), nil
case optionIndicator{functor: "numbervars", arg: "false"}:
return WithNumberVars(false), nil
default:
return nil, domainErrorWriteOption(option)
func variableNames(vnList Term, env *Env) map[Variable]Atom {
vns := map[Variable]Atom{}
iter := ListIterator{List: vnList, Env: env}
for iter.Next() {
vn, ok := env.Resolve(iter.Current()).(*Compound)
if !ok || vn.Functor != "=" || len(vn.Args) != 2 {
return nil
}
n, ok := env.Resolve(vn.Args[0]).(Atom)
if !ok {
return nil
}
v, ok := env.Resolve(vn.Args[1]).(Variable)
if !ok {
return nil
}
if _, ok := vns[v]; ok {
continue
}
vns[v] = n
}
if err := iter.Err(); err != nil {
return nil
}
return vns
}

// CharCode converts a single-rune Atom char to an Integer code, or vice versa.
Expand Down
Loading

0 comments on commit 64903d4

Please sign in to comment.