Skip to content

Commit

Permalink
feat(logic): implements source_file/1 predicate
Browse files Browse the repository at this point in the history
  • Loading branch information
amimart committed Mar 16, 2023
1 parent e09228e commit 8ceede1
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions x/logic/interpreter/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ var Registry = map[string]RegistryEntry{
"sha_hash/2": {predicate.SHAHash, 1},
"hex_bytes/2": {predicate.HexBytes, 1},
"bech32_address/2": {predicate.Bech32Address, 1},
"source_file/1": {predicate.SourceFile, 1},
}

// RegistryNames is the list of the predicate names in the Registry.
Expand Down
72 changes: 72 additions & 0 deletions x/logic/predicate/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package predicate

import (
"fmt"
"reflect"
"sort"

"github.com/ichiban/prolog/engine"
)

func SourceFile(vm *engine.VM, file engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise {
loaded := getLoadedSources(vm)

inputFile, err := getFile(env, file)
if err != nil {
return engine.Error(fmt.Errorf("source_file/1: %w", err))
}

if inputFile != nil {
if _, ok := loaded[*inputFile]; ok {
return engine.Unify(vm, file, engine.NewAtom(*inputFile), cont, env)
}
return engine.Unify(vm, file, engine.List(), cont, env)
}

result := make([]engine.Term, 0, len(loaded))
for _, filename := range sortLoadedSources(loaded) {
result = append(result, engine.NewAtom(filename))
}

return engine.Unify(
vm,
file,
engine.List(result...),
cont,
env,
)
}

func getLoadedSources(vm *engine.VM) map[string]interface{} {
loadedField := reflect.ValueOf(vm).Elem().FieldByName("loaded").MapKeys()
loaded := make(map[string]interface{}, len(loadedField))
for _, value := range loadedField {
loaded[value.String()] = nil
}

return loaded
}

func sortLoadedSources(sources map[string]interface{}) []string {
result := make([]string, 0, len(sources))
for filename := range sources {
result = append(result, filename)
}
sort.SliceStable(result, func(i, j int) bool {
return result[i] < result[j]
})

return result
}

func getFile(env *engine.Env, term engine.Term) (*string, error) {
switch file := env.Resolve(term).(type) {
case engine.Variable:
case engine.Atom:
strFile := file.String()
return &strFile, nil
default:
return nil, fmt.Errorf("cannot unify file with %T", term)
}
return nil, nil
}

0 comments on commit 8ceede1

Please sign in to comment.