Skip to content

Commit

Permalink
ugly first iteration of lexer with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
robertDurst committed Dec 27, 2023
1 parent 3260fb8 commit bc8dc67
Show file tree
Hide file tree
Showing 11 changed files with 616 additions and 91 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ build-iPhoneSimulator/

# Used by RuboCop. Remote config files pulled in from inherit_from directive.
# .rubocop-https?--*
coverage
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,8 @@ DEPENDENCIES
rubocop-rspec
simplecov

RUBY VERSION
ruby 3.2.2p53

BUNDLED WITH
2.4.19
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

require 'simplecov'
SimpleCov.start
71 changes: 71 additions & 0 deletions spec/zodiac/character_helpers_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,53 @@
# frozen_string_literal: true

require './spec/spec_helper'
require './src/zodiac/character_helpers'

describe Zodiac::CharacterHelpers do
include described_class

describe '.symbol?' do
context 'when symbol' do
it 'returns true' do
expect(symbol?('.')).to eq(true)
end
end

context 'when not symbol' do
it 'returns false' do
expect(symbol?('a')).to eq(false)
end
end
end

describe '.string_start?' do
context 'when string start' do
it 'returns true' do
expect(string_start?('"')).to eq(true)
end
end

context 'when not string start' do
it 'returns false' do
expect(string_start?('a')).to eq(false)
end
end
end

describe '.double_symbol?' do
context 'when double symbol' do
it 'returns true' do
expect(double_symbol?('*')).to eq(true)
end
end

context 'when not double symbol' do
it 'returns false' do
expect(double_symbol?('-')).to eq(false)
end
end
end

describe '.alpha_num?' do
context 'when letter' do
it 'returns true' do
Expand All @@ -25,6 +68,20 @@
end
end

describe '.contains_equal_sign?' do
context 'when contains equal sign' do
it 'returns true' do
expect(contains_equal_sign?('a=b')).to eq(true)
end
end

context 'when does not contain equal sign' do
it 'returns false' do
expect(contains_equal_sign?('a')).to eq(false)
end
end
end

describe '.letter?' do
context 'when letter' do
it 'returns true' do
Expand Down Expand Up @@ -64,4 +121,18 @@
end
end
end

describe '.underscore?' do
context 'when underscore' do
it 'returns true' do
expect(underscore?('_')).to eq(true)
end
end

context 'when not underscore' do
it 'returns false' do
expect(underscore?('a')).to eq(false)
end
end
end
end
1 change: 1 addition & 0 deletions spec/zodiac/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require './spec/spec_helper'
require './src/zodiac/cli'

describe Zodiac::CLI do
Expand Down
164 changes: 164 additions & 0 deletions spec/zodiac/lexer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# frozen_string_literal: true

require './spec/spec_helper'
require './src/zodiac/lexer'

describe Zodiac::Lexer do
describe '#lex' do
context 'when empty input' do
it 'returns an empty array of tokens' do
input = ''
lexer = described_class.new(input)

expected_output = []

expect(lexer.lex).to eq(expected_output)
end
end

context 'when invalid input' do
context 'when fails to lex a string' do
it 'raises an error' do
input = '"hello world'
lexer = described_class.new(input)
expect { lexer.lex }.to raise_error(Zodiac::LexError)
end
end
end

context 'when happy path' do
it 'lexs symbols' do
input = ':[ ]{}@~$!?:='
lexer = described_class.new(input)

expected_output = [
{ kind: 'SYMBOL', value: ':' },
{ kind: 'SYMBOL', value: '[' },
{ kind: 'SYMBOL', value: ']' },
{ kind: 'SYMBOL', value: '{' },
{ kind: 'SYMBOL', value: '}' },
{ kind: 'SYMBOL', value: '@' },
{ kind: 'SYMBOL', value: '~' },
{ kind: 'SYMBOL', value: '$' },
{ kind: 'SYMBOL', value: '!' },
{ kind: 'SYMBOL', value: '?' },
{ kind: 'SYMBOL', value: ':' },
{ kind: 'SYMBOL', value: '=' }
]

expect(lexer.lex).to eq(expected_output)
end

it 'lexs whole words' do
input = 'hello WorLD c4k3 _r3d_foo'
lexer = described_class.new(input)

expected_output = [
{ kind: 'IDENTIFIER', value: 'hello' },
{ kind: 'IDENTIFIER', value: 'WorLD' },
{ kind: 'IDENTIFIER', value: 'c4k3' },
{ kind: 'IDENTIFIER', value: '_r3d_foo' }
]

expect(lexer.lex).to eq(expected_output)
end

it 'splits words on symbols' do
input = 'hello:world'
lexer = described_class.new(input)

expected_output = [
{ kind: 'IDENTIFIER', value: 'hello' },
{ kind: 'SYMBOL', value: ':' },
{ kind: 'IDENTIFIER', value: 'world' }
]

expect(lexer.lex).to eq(expected_output)
end

it 'lexs operators' do
input = '+ - * / % ** & | ^ << >> && || @@::..== === =~ +@ -@ [] <=>'
lexer = described_class.new(input)

expected_output = [
{ kind: 'SYMBOL', value: '+' },
{ kind: 'SYMBOL', value: '-' },
{ kind: 'SYMBOL', value: '*' },
{ kind: 'SYMBOL', value: '/' },
{ kind: 'SYMBOL', value: '%' },
{ kind: 'SYMBOL', value: '**' },
{ kind: 'SYMBOL', value: '&' },
{ kind: 'SYMBOL', value: '|' },
{ kind: 'SYMBOL', value: '^' },
{ kind: 'SYMBOL', value: '<<' },
{ kind: 'SYMBOL', value: '>>' },
{ kind: 'SYMBOL', value: '&&' },
{ kind: 'SYMBOL', value: '||' },
{ kind: 'SYMBOL', value: '@@' },
{ kind: 'SYMBOL', value: '::' },
{ kind: 'SYMBOL', value: '..' },
{ kind: 'SYMBOL', value: '==' },
{ kind: 'SYMBOL', value: '===' },
{ kind: 'SYMBOL', value: '=~' },
{ kind: 'SYMBOL', value: '+@' },
{ kind: 'SYMBOL', value: '-@' },
{ kind: 'SYMBOL', value: '[]' },
{ kind: 'SYMBOL', value: '<=>' }
]

expect(lexer.lex).to eq(expected_output)
end

it 'lexs operators with assignment' do
input = '+= -= *= /= %= **= &= |= ^= <<= >>= &&= ||= []= >= <='
lexer = described_class.new(input)

expected_output = [
{ kind: 'OP_ASGN', value: '+=' },
{ kind: 'OP_ASGN', value: '-=' },
{ kind: 'OP_ASGN', value: '*=' },
{ kind: 'OP_ASGN', value: '/=' },
{ kind: 'OP_ASGN', value: '%=' },
{ kind: 'OP_ASGN', value: '**=' },
{ kind: 'OP_ASGN', value: '&=' },
{ kind: 'OP_ASGN', value: '|=' },
{ kind: 'OP_ASGN', value: '^=' },
{ kind: 'OP_ASGN', value: '<<=' },
{ kind: 'OP_ASGN', value: '>>=' },
{ kind: 'OP_ASGN', value: '&&=' },
{ kind: 'OP_ASGN', value: '||=' },
{ kind: 'OP_ASGN', value: '[]=' },
{ kind: 'OP_ASGN', value: '>=' },
{ kind: 'OP_ASGN', value: '<=' }
]

expect(lexer.lex).to eq(expected_output)
end

it 'lexs strings' do
input = '"hello world" \'hello world\' `hello world`'
lexer = described_class.new(input)

expected_output = [
{ kind: 'STRING', value: '"hello world"' },
{ kind: 'STRING', value: "'hello world'" },
{ kind: 'STRING', value: '`hello world`' }
]

expect(lexer.lex).to eq(expected_output)
end

it 'lexs numbers' do
input = '123 123.456'
lexer = described_class.new(input)

expected_output = [
{ kind: 'NUMBER', value: '123' },
{ kind: 'NUMBER', value: '123.456' }
]

expect(lexer.lex).to eq(expected_output)
end
end
end
end
38 changes: 0 additions & 38 deletions spec/zodiac/parser_spec.rb

This file was deleted.

24 changes: 22 additions & 2 deletions src/zodiac/character_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,28 @@
module Zodiac
# Character helper methods common to parsing within the Zodiac language compiler.
module CharacterHelpers
def string_start?(value)
['"', "'", '`'].include?(value)
end

def symbol?(value)
".:[]{}\"'".include?(value)
'.:[]{}+-*/%&|^><@~$!?:'.include?(value)
end

def op_assign_symbol?(value)
'+-*/%*|^><&|[]'.include?(value)
end

def double_symbol?(value)
'*<>|&@:.'.include?(value)
end

def contains_equal_sign?(value)
value.include?('=')
end

def alpha_num?(value)
letter?(value) || number?(value)
letter?(value) || number?(value) || underscore?(value)
end

def letter?(value)
Expand All @@ -18,5 +34,9 @@ def letter?(value)
def number?(value)
value.match?(/[0-9]/)
end

def underscore?(value)
value.match?(/_/)
end
end
end
6 changes: 6 additions & 0 deletions src/zodiac/lex_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

module Zodiac
class LexError < StandardError
end
end
Loading

0 comments on commit bc8dc67

Please sign in to comment.