Skip to content

Commit ff37990

Browse files
authored
Merge pull request #5 from axone-protocol/refactor/atoms-tables
Remove atoms table
2 parents 21a231d + cdbf28d commit ff37990

File tree

7 files changed

+58
-66
lines changed

7 files changed

+58
-66
lines changed

engine/atom.go

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,12 @@ import (
55
"io"
66
"regexp"
77
"strings"
8-
"sync"
9-
"unicode/utf8"
108
)
119

1210
var (
1311
quotedAtomEscapePattern = regexp.MustCompile(`[[:cntrl:]]|\\|'`)
1412
)
1513

16-
var (
17-
atomTable = struct {
18-
sync.RWMutex
19-
names []string
20-
atoms map[string]Atom
21-
}{
22-
atoms: map[string]Atom{},
23-
}
24-
)
25-
2614
// Well-known atoms.
2715
var (
2816
atomEmpty = NewAtom("")
@@ -208,27 +196,15 @@ var (
208196
)
209197

210198
// Atom is a prolog atom.
211-
type Atom uint64
199+
type Atom string
212200

213201
// NewAtom interns the given string and returns an Atom.
214202
func NewAtom(name string) Atom {
215-
// A one-char atom is just a rune.
216-
if r, n := utf8.DecodeLastRuneInString(name); r != utf8.RuneError && n == len(name) {
217-
return Atom(r)
218-
}
219-
220-
atomTable.Lock()
221-
defer atomTable.Unlock()
222-
223-
a, ok := atomTable.atoms[name]
224-
if ok {
225-
return a
226-
}
203+
return Atom(name)
204+
}
227205

228-
a = Atom(len(atomTable.names) + (utf8.MaxRune + 1))
229-
atomTable.atoms[name] = a
230-
atomTable.names = append(atomTable.names, name)
231-
return a
206+
func NewAtomRune(v rune) Atom {
207+
return Atom(v)
232208
}
233209

234210
// WriteTerm outputs the Atom to an io.Writer.
@@ -237,7 +213,7 @@ func (a Atom) WriteTerm(w io.Writer, opts *WriteOptions, _ *Env) error {
237213
openClose := (opts.left != (operator{}) || opts.right != (operator{})) && opts.getOps().defined(a)
238214

239215
if openClose {
240-
if opts.left.name != 0 && opts.left.specifier.class() == operatorClassPrefix {
216+
if opts.left.name != "" && opts.left.specifier.class() == operatorClassPrefix {
241217
_, _ = ew.Write([]byte(" "))
242218
}
243219
_, _ = ew.Write([]byte("("))
@@ -289,12 +265,7 @@ func (a Atom) Compare(t Term, env *Env) int {
289265
}
290266

291267
func (a Atom) String() string {
292-
if a <= utf8.MaxRune {
293-
return string(rune(a))
294-
}
295-
atomTable.RLock()
296-
defer atomTable.RUnlock()
297-
return atomTable.names[a-(utf8.MaxRune+1)]
268+
return string(a)
298269
}
299270

300271
// Apply returns a Compound which Functor is the Atom and args are the arguments. If the arguments are empty,

engine/builtin.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,7 @@ func CharCode(vm *VM, char, code Term, k Cont, env *Env) *Promise {
16211621
return Error(representationError(flagCharacterCode, env))
16221622
}
16231623

1624-
return Unify(vm, ch, Atom(r), k, env)
1624+
return Unify(vm, ch, NewAtomRune(r), k, env)
16251625
default:
16261626
return Error(typeError(validTypeInteger, code, env))
16271627
}
@@ -1685,12 +1685,11 @@ func PutChar(vm *VM, streamOrAlias, char Term, k Cont, env *Env) *Promise {
16851685
case Variable:
16861686
return Error(InstantiationError(env))
16871687
case Atom:
1688-
if c > utf8.MaxRune {
1688+
r, n := utf8.DecodeLastRuneInString(c.String())
1689+
if r == utf8.RuneError || n != len(c.String()) {
16891690
return Error(typeError(validTypeCharacter, c, env))
16901691
}
16911692

1692-
r := rune(c)
1693-
16941693
switch _, err := s.WriteRune(r); {
16951694
case errors.Is(err, errWrongIOMode):
16961695
return Error(permissionError(operationOutput, permissionTypeStream, streamOrAlias, env))
@@ -1861,7 +1860,7 @@ func GetChar(vm *VM, streamOrAlias, char Term, k Cont, env *Env) *Promise {
18611860
return Error(representationError(flagCharacter, env))
18621861
}
18631862

1864-
return Unify(vm, char, Atom(r), k, env)
1863+
return Unify(vm, char, NewAtomRune(r), k, env)
18651864
case io.EOF:
18661865
return Unify(vm, char, atomEndOfFile, k, env)
18671866
case errWrongIOMode:
@@ -1941,7 +1940,7 @@ func PeekChar(vm *VM, streamOrAlias, char Term, k Cont, env *Env) *Promise {
19411940
return Error(representationError(flagCharacter, env))
19421941
}
19431942

1944-
return Unify(vm, char, Atom(r), k, env)
1943+
return Unify(vm, char, NewAtomRune(r), k, env)
19451944
case io.EOF:
19461945
return Unify(vm, char, atomEndOfFile, k, env)
19471946
case errWrongIOMode:
@@ -2335,7 +2334,7 @@ func numberCharsWrite(vm *VM, num, chars Term, k Cont, env *Env) *Promise {
23352334

23362335
cs := make([]Term, len(rs))
23372336
for i, r := range rs {
2338-
cs[i] = Atom(r)
2337+
cs[i] = NewAtomRune(r)
23392338
}
23402339
return Unify(vm, chars, List(cs...), k, env)
23412340
}
@@ -2584,7 +2583,7 @@ func CurrentCharConversion(vm *VM, inChar, outChar Term, k Cont, env *Env) *Prom
25842583
if c1, ok := env.Resolve(inChar).(Atom); ok {
25852584
r := []rune(c1.String())
25862585
if r, ok := vm.charConversions[r[0]]; ok {
2587-
return Unify(vm, outChar, Atom(r), k, env)
2586+
return Unify(vm, outChar, NewAtomRune(r), k, env)
25882587
}
25892588
return Unify(vm, outChar, c1, k, env)
25902589
}
@@ -2599,7 +2598,7 @@ func CurrentCharConversion(vm *VM, inChar, outChar Term, k Cont, env *Env) *Prom
25992598
}
26002599

26012600
ks[i] = func(context.Context) *Promise {
2602-
return Unify(vm, pattern, tuple(Atom(r), Atom(cr)), k, env)
2601+
return Unify(vm, pattern, tuple(NewAtomRune(r), NewAtomRune(cr)), k, env)
26032602
}
26042603
}
26052604
return Delay(ks...)

engine/compound.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ func writeCompoundOpInfix(w io.Writer, c Compound, opts *WriteOptions, env *Env,
204204
(opts.right != operator{} && r >= opts.right.priority)
205205

206206
if openClose {
207-
if opts.left.name != 0 && opts.left.specifier.class() == operatorClassPrefix {
207+
if opts.left.name != "" && opts.left.specifier.class() == operatorClassPrefix {
208208
_, _ = fmt.Fprint(&ew, " ")
209209
}
210210
_, _ = fmt.Fprint(&ew, "(")
@@ -494,7 +494,7 @@ func pair(k, v Term) Term {
494494
}
495495

496496
func tuple(args ...Term) Term {
497-
return Atom(0).Apply(args...)
497+
return Atom("").Apply(args...)
498498
}
499499

500500
type charList string
@@ -524,7 +524,7 @@ func (c charList) Arg(n int) Term {
524524
var t Term
525525
switch n {
526526
case 0:
527-
t = Atom(r)
527+
t = NewAtomRune(r)
528528
case 1:
529529
if i == len(c) {
530530
t = atomEmptyList

engine/parser.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -463,21 +463,21 @@ func (p *Parser) op(maxPriority Integer) (Atom, error) {
463463
if p.current().kind == tokenCloseList {
464464
p.backup()
465465
}
466-
return 0, errNoOp
466+
return "", errNoOp
467467
case atomEmptyBlock:
468468
p.backup()
469469
if p.current().kind == tokenCloseCurly {
470470
p.backup()
471471
}
472-
return 0, errNoOp
472+
return "", errNoOp
473473
default:
474474
return a, nil
475475
}
476476
}
477477

478478
t, err := p.next()
479479
if err != nil {
480-
return 0, err
480+
return "", err
481481
}
482482
switch t.kind {
483483
case tokenComma:
@@ -489,7 +489,7 @@ func (p *Parser) op(maxPriority Integer) (Atom, error) {
489489
}
490490

491491
p.backup()
492-
return 0, errExpectation
492+
return "", errExpectation
493493
}
494494

495495
func (p *Parser) term0(maxPriority Integer) (Term, error) {
@@ -571,7 +571,7 @@ func (p *Parser) term0Atom(maxPriority Integer) (Term, error) {
571571
return nil, errExpectation
572572
}
573573

574-
if p.placeholder != 0 && t == p.placeholder {
574+
if p.placeholder != "" && t == p.placeholder {
575575
if len(p.args) == 0 {
576576
return nil, errPlaceholder
577577
}
@@ -616,53 +616,53 @@ func (p *Parser) atom() (Atom, error) {
616616

617617
t, err := p.next()
618618
if err != nil {
619-
return 0, err
619+
return "", err
620620
}
621621
switch t.kind {
622622
case tokenOpenList:
623623
t, err := p.next()
624624
if err != nil {
625-
return 0, err
625+
return "", err
626626
}
627627
switch t.kind {
628628
case tokenCloseList:
629629
return atomEmptyList, nil
630630
default:
631631
p.backup()
632632
p.backup()
633-
return 0, errExpectation
633+
return "", errExpectation
634634
}
635635
case tokenOpenCurly:
636636
t, err := p.next()
637637
if err != nil {
638-
return 0, err
638+
return "", err
639639
}
640640
switch t.kind {
641641
case tokenCloseCurly:
642642
return atomEmptyBlock, nil
643643
default:
644644
p.backup()
645645
p.backup()
646-
return 0, errExpectation
646+
return "", errExpectation
647647
}
648648
case tokenDoubleQuotedList:
649649
switch p.doubleQuotes {
650650
case doubleQuotesAtom:
651651
return NewAtom(unDoubleQuote(t.val)), nil
652652
default:
653653
p.backup()
654-
return 0, errExpectation
654+
return "", errExpectation
655655
}
656656
default:
657657
p.backup()
658-
return 0, errExpectation
658+
return "", errExpectation
659659
}
660660
}
661661

662662
func (p *Parser) name() (Atom, error) {
663663
t, err := p.next()
664664
if err != nil {
665-
return 0, err
665+
return "", err
666666
}
667667
switch t.kind {
668668
case tokenLetterDigit, tokenGraphic, tokenSemicolon, tokenCut:
@@ -671,7 +671,7 @@ func (p *Parser) name() (Atom, error) {
671671
return NewAtom(unquote(t.val)), nil
672672
default:
673673
p.backup()
674-
return 0, errExpectation
674+
return "", errExpectation
675675
}
676676
}
677677

engine/stream.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ func (s *Stream) properties() []Term {
359359
ps = append(ps, atomOutput)
360360
}
361361

362-
if s.alias != 0 {
362+
if s.alias != "" {
363363
ps = append(ps, atomAlias.Apply(s.alias))
364364
}
365365

@@ -510,7 +510,7 @@ type streams struct {
510510
}
511511

512512
func (ss *streams) add(s *Stream) {
513-
if s.alias != 0 {
513+
if s.alias != "" {
514514
if ss.aliases == nil {
515515
ss.aliases = map[Atom]*Stream{}
516516
}

engine/term_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ func TestCompareAtomic(t *testing.T) {
4848
{a: &y{}, t: NewVariable(), o: 1},
4949
{a: &y{}, t: NewFloatFromInt64(0), o: 1},
5050
{a: &y{}, t: Integer(0), o: 1},
51-
{a: &y{}, t: Atom(0), o: 1},
51+
{a: &y{}, t: Atom(""), o: 1},
5252
{a: &y{}, t: &x{}, o: 1},
5353
{a: &y{val: 1}, t: &y{val: 0}, cmp: cmp, o: 1},
5454
{a: &y{val: 0}, t: &y{val: 0}, cmp: cmp, o: 0},
5555
{a: &y{val: 0}, t: &y{val: 1}, cmp: cmp, o: -1},
5656
{a: &y{}, t: &z{}, o: -1},
57-
{a: &y{}, t: Atom(0).Apply(Integer(0)), o: -1},
57+
{a: &y{}, t: Atom("").Apply(Integer(0)), o: -1},
5858
}
5959

6060
for _, tt := range tests {

engine/vm_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,25 @@ func TestProcedureIndicator_Apply(t *testing.T) {
286286
assert.Nil(t, c)
287287
})
288288
}
289+
290+
func TestVM_ResetEnv(t *testing.T) {
291+
var vm VM
292+
varCounter = 10
293+
varContext = NewVariable()
294+
rootContext = NewAtom("non-root")
295+
rootEnv = &Env{
296+
binding: binding{
297+
key: newEnvKey(varContext),
298+
value: NewAtom("non-root"),
299+
},
300+
}
301+
302+
t.Run("Reset environment", func(t *testing.T) {
303+
vm.ResetEnv()
304+
305+
assert.Equal(t, int64(1), varCounter) // 1 because NewVariable() is called in ResetEnv()
306+
assert.Equal(t, "root", rootContext.String())
307+
assert.Equal(t, newEnvKey(varContext), rootEnv.binding.key)
308+
assert.Equal(t, NewAtom("root"), rootEnv.binding.value)
309+
})
310+
}

0 commit comments

Comments
 (0)