Skip to content

Instantly share code, notes, and snippets.

@andrewjl
Created September 2, 2011 22:50

Revisions

  1. andrewjl revised this gist Sep 4, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion test_sentence.rb
    Original file line number Diff line number Diff line change
    @@ -33,7 +33,7 @@ def test_parse_verb
    assert_equal(parse_verb(list_one), Pair.new(:verb, 'go'))

    list_two = [Pair.new(:noun, 'player') ,Pair.new(:verb, 'go'), Pair.new(:noun, 'king')]
    assert_raise(ParserError.new("Expected a noun or direction next.")) {parse_verb(list_two)}
    assert_raise(ParserError.new("Expected a verb next.")) {parse_verb(list_two)}
    end

    end
  2. andrewjl revised this gist Sep 3, 2011. 2 changed files with 24 additions and 8 deletions.
    14 changes: 9 additions & 5 deletions sentence.rb
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,11 @@ def initialize(subject, verb, object)
    end

    def peek(word_list)
    word_list.first.token
    begin
    word_list.first.token
    rescue
    nil
    end
    end

    def match(word_list, expecting)
    @@ -26,14 +30,14 @@ def match(word_list, expecting)
    end
    end

    def skip(word_list, token)
    def skip_word(word_list, token)
    while peek(word_list) == token
    match(word_list, token)
    end
    end

    def parse_verb(word_list)
    skip(word_list, :stop)
    skip_word(word_list, :stop)

    if peek(word_list) == :verb
    return match(word_list, :verb)
    @@ -43,7 +47,7 @@ def parse_verb(word_list)
    end

    def parse_object(word_list)
    skip(word_list, :stop)
    skip_word(word_list, :stop)
    next_word = peek(word_list)

    if next_word == :noun
    @@ -64,7 +68,7 @@ def parse_subject(word_list, subj)
    end

    def parse_sentence(word_list)
    skip(word_list, :stop)
    skip_word(word_list, :stop)

    start = peek(word_list)

    18 changes: 15 additions & 3 deletions test_sentence.rb
    Original file line number Diff line number Diff line change
    @@ -18,10 +18,22 @@ def test_match
    assert_equal(match(big_list, :noun), nil)
    end

    def test_skip
    def test_skip_word
    small_list = [Pair.new(:verb, 'go'), Pair.new(:verb, 'do')]
    skip(small_list, :verb)
    assert_equal([],small_list)
    skip_word(small_list, :verb)
    assert_equal([],small_list)

    big_list = [Pair.new(:verb, 'go'), Pair.new(:noun, 'king')]
    skip_word(big_list, :verb)
    assert_equal([Pair.new(:noun, 'king')], big_list)
    end

    def test_parse_verb
    list_one = [Pair.new(:verb, 'go'), Pair.new(:noun, 'king')]
    assert_equal(parse_verb(list_one), Pair.new(:verb, 'go'))

    list_two = [Pair.new(:noun, 'player') ,Pair.new(:verb, 'go'), Pair.new(:noun, 'king')]
    assert_raise(ParserError.new("Expected a noun or direction next.")) {parse_verb(list_two)}
    end

    end
  3. andrewjl created this gist Sep 2, 2011.
    41 changes: 41 additions & 0 deletions lexicon.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    class Lexicon
    Pair = Struct.new(:token, :word)
    Direction = %w(north south east west down up left right back)
    Verb = %w(go stop kill eat)
    Stop = %w(the in of from at it)
    Noun = %w(door bear princess cabinet)

    def initialize()
    end

    def scan(phrase)
    word_set = phrase.split(' ')
    result = []

    for word in word_set
    if Direction.include?(word)
    result.push(Pair.new(:direction, word))
    elsif Verb.include?(word)
    result.push(Pair.new(:verb, word))
    elsif Stop.include?(word)
    result.push(Pair.new(:stop, word))
    elsif Noun.include?(word)
    result.push(Pair.new(:noun, word))
    elsif convert_number(word) != nil
    word = convert_number(word)
    result.push(Pair.new(:number, word))
    else
    result.push(Pair.new(:error, word))
    end
    end
    return result
    end

    def convert_number(s)
    begin
    Integer(s)
    rescue ArgumentError
    nil
    end
    end
    end
    80 changes: 80 additions & 0 deletions sentence.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    class ParserError < Exception

    end

    class Sentence

    def initialize(subject, verb, object)
    # remember we take Pair.new(:noun, "princess") structs and convert them
    @subject = subject.word
    @verb = verb.word
    @object = object.word
    end

    end

    def peek(word_list)
    word_list.first.token
    end

    def match(word_list, expecting)
    word = word_list.shift
    if word.token == expecting
    word
    else
    nil
    end
    end

    def skip(word_list, token)
    while peek(word_list) == token
    match(word_list, token)
    end
    end

    def parse_verb(word_list)
    skip(word_list, :stop)

    if peek(word_list) == :verb
    return match(word_list, :verb)
    else
    raise ParserError.new("Expected a verb next.")
    end
    end

    def parse_object(word_list)
    skip(word_list, :stop)
    next_word = peek(word_list)

    if next_word == :noun
    return match(word_list, :noun)
    end
    if next_word == :direction
    return match(word_list, :direction)
    else
    raise ParserError.new("Expected a noun or direction next.")
    end
    end

    def parse_subject(word_list, subj)
    verb = parse_verb(word_list)
    obj = parse_object(word_list)

    return Sentence.new(subj, veb, obj)
    end

    def parse_sentence(word_list)
    skip(word_list, :stop)

    start = peek(word_list)

    if start == :noun
    subj = match(word_list, :noun)
    return parse_subject(word_list, subj)
    elsif start == :verb
    # assume the subject is the player then
    return parse_subject(word_list, Pair.new(:noun, "player"))
    else
    return ParserError.new("Must start with subject, object, or verb not: #{start}")
    end
    end
    27 changes: 27 additions & 0 deletions test_sentence.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    require 'test/unit'
    require_relative '../lib/lexicon'
    require_relative '../lib/sentence'

    class SentenceTests < Test::Unit::TestCase

    Pair = Lexicon::Pair

    def test_peek
    assert_equal(peek([Pair.new(:verb, 'go')]), :verb)
    end

    def test_match
    test_list = [Pair.new(:verb, 'go')]
    assert_equal(match(test_list, :verb), Pair.new(:verb, 'go'))

    big_list = [Pair.new(:verb, 'go'), Pair.new(:noun, 'king'), Pair.new(:stop, 'is')]
    assert_equal(match(big_list, :noun), nil)
    end

    def test_skip
    small_list = [Pair.new(:verb, 'go'), Pair.new(:verb, 'do')]
    skip(small_list, :verb)
    assert_equal([],small_list)
    end

    end