package saccharine import ( "fmt" "unicode" "git.maximhutz.com/max/lambda/pkg/iterator" "git.maximhutz.com/max/lambda/pkg/token" ) // Pulls the next token from an iterator over runes. If it cannot, it will // return nil. If an error occurs, it will return that. func scanToken(i *iterator.Iterator[rune]) (*Token, error) { index := i.Index() if i.Done() { return nil, nil } letter, err := i.Next() if err != nil { return nil, fmt.Errorf("cannot produce next token: %w", err) } switch { case letter == '(': return token.New(TokenOpenParen, index), nil case letter == ')': return token.New(TokenCloseParen, index), nil case letter == '.': return token.New(TokenDot, index), nil case letter == '\\': return token.New(TokenSlash, index), nil case letter == '\n': return token.New(TokenSoftBreak, index), nil case letter == '{': return token.New(TokenOpenBrace, index), nil case letter == '}': return token.New(TokenCloseBrace, index), nil case letter == ':': if _, err := token.ScanCharacter(i, '='); err != nil { return nil, err } else { return token.New(TokenAssign, index), nil } case letter == ';': return token.New(TokenHardBreak, index), nil case letter == '#': // Skip everything until the next newline or EOF. i.While(func(r rune) bool { return r != '\n' }) return nil, nil case unicode.IsSpace(letter): return nil, nil case token.IsVariable(letter): return token.ScanAtom(i, letter, TokenAtom, index), nil } return nil, fmt.Errorf("unknown character '%v'", string(letter)) } // scan a string into tokens. func scan(input string) ([]Token, error) { return token.Scan(input, scanToken) }