2022-08-07 13:18:59 -06:00
|
|
|
package lexer
|
|
|
|
|
2022-08-09 18:45:06 -06:00
|
|
|
import "io"
|
2022-08-08 01:08:50 -06:00
|
|
|
import "github.com/sashakoshka/arf/file"
|
2022-08-07 13:18:59 -06:00
|
|
|
|
|
|
|
// LexingOperation holds information about an ongoing lexing operataion.
|
|
|
|
type LexingOperation struct {
|
2022-08-09 20:12:14 -06:00
|
|
|
file *file.File
|
|
|
|
char rune
|
|
|
|
tokens []Token
|
2022-08-07 13:18:59 -06:00
|
|
|
}
|
|
|
|
|
2022-08-09 18:45:06 -06:00
|
|
|
// Tokenize converts a file into a slice of tokens (lexemes).
|
|
|
|
func Tokenize (file *file.File) (tokens []Token, err error) {
|
|
|
|
lexer := LexingOperation { file: file }
|
2022-08-09 20:12:14 -06:00
|
|
|
err = lexer.tokenize()
|
|
|
|
tokens = lexer.tokens
|
2022-08-09 18:45:06 -06:00
|
|
|
|
|
|
|
// if the lexing operation returned io.EOF, nothing went wrong so we
|
|
|
|
// return nil for err.
|
|
|
|
if err == io.EOF {
|
|
|
|
err = nil
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// tokenize converts a file into a slice of tokens (lexemes). It will always
|
|
|
|
// return a non-nil error, but if nothing went wrong it will return io.EOF.
|
2022-08-09 20:12:14 -06:00
|
|
|
func (lexer *LexingOperation) tokenize () (err error) {
|
2022-08-09 18:45:06 -06:00
|
|
|
err = lexer.nextRune()
|
|
|
|
if err != nil { return }
|
|
|
|
|
|
|
|
for {
|
|
|
|
lowercase := lexer.char >= 'a' && lexer.char <= 'z'
|
|
|
|
uppercase := lexer.char >= 'A' && lexer.char <= 'Z'
|
|
|
|
number := lexer.char >= '0' && lexer.char <= '9'
|
|
|
|
|
|
|
|
if number {
|
|
|
|
// TODO: tokenize number
|
|
|
|
} else if lowercase || uppercase {
|
|
|
|
// TODO: tokenize multi
|
|
|
|
} else {
|
2022-08-09 20:18:12 -06:00
|
|
|
err = lexer.tokenizeSymbolBeginning()
|
|
|
|
if err != nil { return err }
|
2022-08-09 18:45:06 -06:00
|
|
|
}
|
|
|
|
|
2022-08-09 19:44:41 -06:00
|
|
|
// TODO: skip whitespace
|
2022-08-09 18:45:06 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
2022-08-07 13:18:59 -06:00
|
|
|
}
|
|
|
|
|
2022-08-09 20:18:12 -06:00
|
|
|
func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|
|
|
switch lexer.char {
|
|
|
|
case '\t':
|
|
|
|
for lexer.char == '\t' {
|
|
|
|
lexer.addToken (Token {
|
|
|
|
kind: TokenKindIndent,
|
|
|
|
})
|
|
|
|
lexer.nextRune()
|
|
|
|
}
|
|
|
|
case '"':
|
|
|
|
// TODO: tokenize string literal
|
|
|
|
lexer.nextRune()
|
|
|
|
case '\'':
|
|
|
|
// TODO: tokenize rune literal
|
|
|
|
lexer.nextRune()
|
|
|
|
case ':':
|
|
|
|
lexer.addToken (Token {
|
|
|
|
kind: TokenKindColon,
|
|
|
|
})
|
|
|
|
lexer.nextRune()
|
|
|
|
case '.':
|
|
|
|
lexer.addToken (Token {
|
|
|
|
kind: TokenKindDot,
|
|
|
|
})
|
|
|
|
lexer.nextRune()
|
|
|
|
case '[':
|
|
|
|
lexer.addToken (Token {
|
|
|
|
kind: TokenKindLBracket,
|
|
|
|
})
|
|
|
|
lexer.nextRune()
|
|
|
|
case ']':
|
|
|
|
lexer.addToken (Token {
|
|
|
|
kind: TokenKindRBracket,
|
|
|
|
})
|
|
|
|
lexer.nextRune()
|
|
|
|
case '{':
|
|
|
|
lexer.addToken (Token {
|
|
|
|
kind: TokenKindLBrace,
|
|
|
|
})
|
|
|
|
lexer.nextRune()
|
|
|
|
case '}':
|
|
|
|
lexer.addToken (Token {
|
|
|
|
kind: TokenKindRBrace,
|
|
|
|
})
|
|
|
|
lexer.nextRune()
|
|
|
|
// TODO: add more for things like math symbols, return
|
|
|
|
// direction operators, indentation, etc
|
|
|
|
default:
|
|
|
|
err = file.NewError (
|
|
|
|
lexer.file.Location(), 1,
|
|
|
|
"unexpected character " +
|
|
|
|
string(lexer.char),
|
|
|
|
file.ErrorKindError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-08-09 20:12:14 -06:00
|
|
|
func (lexer *LexingOperation) addToken (token Token) {
|
|
|
|
lexer.tokens = append(lexer.tokens, token)
|
|
|
|
}
|
|
|
|
|
2022-08-09 18:45:06 -06:00
|
|
|
// nextRune advances the lexer to the next rune in the file.
|
|
|
|
func (lexer *LexingOperation) nextRune () (err error) {
|
|
|
|
lexer.char, _, err = lexer.file.ReadRune()
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
return file.NewError (
|
|
|
|
lexer.file.Location(), 1,
|
|
|
|
err.Error(), file.ErrorKindError)
|
|
|
|
}
|
2022-08-07 13:18:59 -06:00
|
|
|
return
|
|
|
|
}
|