Skip to content

Commit

Permalink
remove state from Lexer class
Browse files Browse the repository at this point in the history
  • Loading branch information
robertDurst committed Dec 29, 2023
1 parent 8bd1d98 commit 0b39b91
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 38 deletions.
64 changes: 26 additions & 38 deletions src/zodiac/lexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class Lexer
include ::Zodiac::CharacterHelpers

def initialize(raw_string)
@tokens = []
@word = ''
@input_iterator = StringCharacterIterator.new(raw_string)
end

def lex
lex_next while @input_iterator.not_finished?
tokens = []

@tokens
tokens << lex_next while @input_iterator.not_finished?

tokens.compact
end

private
Expand All @@ -44,81 +44,69 @@ def lexers
end

def lex_next
reset_lex_iteration_state

lexers.each do |lexer|
next unless lexer[:condition].call(@input_iterator.peek)

send(lexer[:lexer])
@tokens << { kind: lexer[:token_kind], value: @word }
return true
return { kind: lexer[:token_kind], value: send(lexer[:lexer]) }
end

# if we get here, we didn't lex anything, i.e. unrecognized character pattern
@input_iterator.iterate

nil
end

### lexers ###

def lex_symbol
@word = @input_iterator.peek
word = @input_iterator.peek
@input_iterator.iterate

return unless complex_symbol?(@word, @input_iterator.peek)
return word unless complex_symbol?(word, @input_iterator.peek)

@word += @input_iterator.peek
word += @input_iterator.peek
@input_iterator.iterate

word
end

def lex_op_assign
continue_until_stop(after: 1) { @input_iterator.peek != '=' }
take_until(after: 1) { @input_iterator.peek != '=' }
end

def lex_string
unless @input_iterator.rest_includes?(@input_iterator.peek)
raise LexError,
'String not terminated'
end
raise LexError, 'String not terminated' unless @input_iterator.rest_includes?(@input_iterator.peek)

continue_until_stop(before: 1, after: 1) { !string_start?(@input_iterator.peek) }
take_until(before: 1, after: 1) { !string_start?(@input_iterator.peek) }
end

def lex_number
continue_until_stop { number?(@input_iterator.peek) }
word = take_until { number?(@input_iterator.peek) }

return unless @input_iterator.peek == '.'
return word += take_until(before: 1) { number?(@input_iterator.peek) } if @input_iterator.peek == '.'

continue_until_stop(before: 1) do
number?(@input_iterator.peek)
end
word
end

def lex_identifier
continue_until_stop { alpha_num?(@input_iterator.peek) }
take_until { alpha_num?(@input_iterator.peek) }
end

def lex_comment
continue_until_stop { @input_iterator.peek != "\n" }
take_until { @input_iterator.peek != "\n" }
end

### Helpers ###
def append_word_and_iterate
@word += @input_iterator.peek
@input_iterator.iterate
end
def take_until(before: 0, after: 0)
word = ''

def continue_until_stop(before: 0, after: 0)
before.times { append_word_and_iterate }
before.times { word += @input_iterator.iterate }

append_word_and_iterate while @input_iterator.not_finished? && yield
word += @input_iterator.iterate while @input_iterator.not_finished? && yield

after.times { append_word_and_iterate }

@word
end
after.times { word += @input_iterator.iterate }

def reset_lex_iteration_state
@word = ''
word
end
end
end
3 changes: 3 additions & 0 deletions src/zodiac/string_character_iterator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ def not_finished?
end

def iterate
old_top = peek
@raw_string = @raw_string[1..]

old_top
end

def peek
Expand Down

0 comments on commit 0b39b91

Please sign in to comment.