aboutsummaryrefslogtreecommitdiff
path: root/snap/parsing.go
blob: a848c33e305a3bfed2c008e9ea82b5b811e6f74b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package snap

import (
	"strings"
	"log"
	"os"
	"strconv"
)

var die = log.New(os.Stderr, "", 0)

func isEscaped(str string) bool {
	n := len(str)
	return n > 1 && str[0] == '"' && str[n - 1] == '"'; 
}

func parseEscaped(snapish string) *Relative {
	if isEscaped(snapish) {
		snapshot := strings.Trim(snapish, `"`);

		if(snapshot == "") {
			die.Fatal("Snapshot cannot be empty \"\"")
		
		}

		return &Relative {
			snapshot: snapshot,
		}
	}

	return nil
}

func parseRelativeSyntax(snapish, directionToken string) *Relative {
	parts := strings.Split(snapish, directionToken)
	n_parts := len(parts)

	if n_parts == 1 {
		return nil;
	}
	
	// Test if the last the last token is a numeric offset
	if offset, err := strconv.Atoi(parts[n_parts - 1]); 
		err == nil {
		
		// Two tokens (e.g. ++ or --) indicates increment syntax
		if n_parts > 2 && parts[n_parts - 2] == "" {
			die.Fatal("A snapshot reference cannot be a mix of increment syntax (e.g. my_snap++) and literal syntax (e.g. my_snap+4).")
		}

		snapshot := strings.TrimRight(snapish, directionToken + "0123456789")
		
		return &Relative {
			offset: offset,
			snapshot: snapshot,
		}
	}

	// Parse the increment / decrement syntax
	// E.g. snapshot+++ or snapshot---
	offset := 0;
	for i := n_parts - 1; i >= 1 && parts[i] == ""; i-- {
		offset += 1
	}
  
	return &Relative {
		offset: offset,
		snapshot: snapish[:len(snapish) - offset],
	}
}

func ToRelative(snapish string) * Relative {
	if ref := parseEscaped(snapish); ref != nil {
		return ref;
	}

	if ref := parseRelativeSyntax(snapish, "+"); ref != nil {
		return ref;
	}

	if ref := parseRelativeSyntax(snapish, "-"); ref != nil {
		ref.offset = -ref.offset;
		return ref;
	}

	return &Relative{
		snapshot: snapish,
	};
}