package main import ( "fmt" "slices" ) type Input struct { index int input []Lexeme } func (in Input) Index() int { return in.index } func (in Input) String() string { _ = in.input[in.index] return fmt.Sprintf("%v", in.input[in.index:]) } func (in *Input) Len() int { // _ = in.input[in.index] return len(in.input[in.index:]) } func (in *Input) Peek(i int) Lexeme { return in.input[in.index+i] } func (in *Input) Pop() (Lexeme, bool) { if in.index > len(in.input)-1 { return nil, false } v := in.input[in.index] in.index++ return v, true } func (in *Input) Seek(i int) { _ = in.input[i] in.index = i } func (in *Input) Take(offset int) *Input { var out = &Input{ index: 0, input: in.input[in.index : in.index+offset], } in.index += offset return out } func (in *Input) Find(open, close *Token) (int, bool) { level := 1 _ = in.input[in.index] idx := slices.IndexFunc(in.input[in.index:], func(a Lexeme) bool { switch { case a.Equals(open): level++ case a.Equals(close): level-- return level == 0 } return false }) if idx > -1 { return idx, true } else { return 0, false } } func (in *Input) TakeParens(open, close *Token) (*Input, error) { if in.input[in.index].Equals(open) { return nil, noMatch } start := in.index level := 1 idx := slices.IndexFunc(in.input[start+1:], func(a Lexeme) bool { switch { case a.Equals(open): level++ case a.Equals(close): level-- return level == 0 } return false }) if idx > -1 { _ = in.Take(idx + 1) return &Input{index: 0, input: in.input[start+1 : idx]}, nil } else { return nil, fmt.Errorf("unmatched parenthesis starting at %s", in.Peek(start).Position()) } }