parser.go 1.81 KB
Newer Older
1
2
3
4
package parser

import (
	"bufio"
5
	"errors"
6
7
	"fmt"
	"io"
8
	"strings"
9
10
)

11
12
const multilineString = `"""`

13
14
type Command struct {
	Name string
15
16
17
18
19
20
	Args string
}

func (c *Command) Reset() {
	c.Name = ""
	c.Args = ""
21
22
23
24
}

func Parse(reader io.Reader) ([]Command, error) {
	var commands []Command
25
	var command, modelCommand Command
26
27

	scanner := bufio.NewScanner(reader)
28
	scanner.Split(scanModelfile)
29
	for scanner.Scan() {
30
31
32
		line := scanner.Bytes()

		fields := bytes.SplitN(line, []byte(" "), 2)
33
34
35
36
		if len(fields) == 0 {
			continue
		}

37
		switch strings.ToUpper(string(fields[0])) {
38
39
		case "FROM":
			command.Name = "model"
40
41
42
			command.Args = string(fields[1])
			// copy command for validation
			modelCommand = command
Jeffrey Morgan's avatar
Jeffrey Morgan committed
43
		case "LICENSE", "TEMPLATE", "SYSTEM", "PROMPT":
44
			command.Name = strings.ToLower(string(fields[0]))
45
			command.Args = string(fields[1])
46
		case "PARAMETER":
47
48
49
			fields = bytes.SplitN(fields[1], []byte(" "), 2)
			command.Name = string(fields[0])
			command.Args = string(fields[1])
50
		default:
51
			return nil, fmt.Errorf("unknown command: %s", fields[0])
52
		}
53
54
55

		commands = append(commands, command)
		command.Reset()
56
57
	}

58
	if modelCommand.Args == "" {
59
		return nil, errors.New("no FROM line for the model was specified")
60
61
62
63
	}

	return commands, scanner.Err()
}
64
65
66
67

func scanModelfile(data []byte, atEOF bool) (advance int, token []byte, err error) {
	newline := bytes.IndexByte(data, '\n')

68
69
	if start := bytes.Index(data, []byte(multilineString)); start >= 0 && start < newline {
		end := bytes.Index(data[start+len(multilineString):], []byte(multilineString))
70
		if end < 0 {
71
			if atEOF {
72
				return 0, nil, errors.New("unterminated multiline string: " + multilineString)
73
74
75
			} else {
				return 0, nil, nil
			}
76
77
		}

78
79
		n := start + len(multilineString) + end + len(multilineString)
		return n, data[:n], nil
80
81
82
83
	}

	return bufio.ScanLines(data, atEOF)
}