aboutsummaryrefslogtreecommitdiff
path: root/spec/practical/int_int_hash_spec.cr
blob: d9b256d996e8679577ee0cae6b769df722118100 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
require "../spec_helper"

include Parcom

describe "Hash(Int32, Int32) parser", tags: "example" do
  d = Parser(Char, Char).satisfy(&.number?).named("digit")
  abs_num = d.some.map { |ds| ds.join.to_i32 }.named("abs_num")

  sign = Parser.token('-').map_const(-1_i32).recover(1_i32).named("sign")

  int32 = parser_chain Char, Int32, "int32",
    {s, sign},
    {n, abs_num},
    pure: n * s 

  ws = Parser(Char, Char).satisfy(&.whitespace?)
    .many
    .named("whitespace")

  arrow = (ws >> Parser.token_sequence("=>".chars) >> ws).named("arrow")

  pair = parser_chain Char, {Int32, Int32}, "pair",
    {x, int32},
    {_, arrow},
    {y, int32},
    pure: {x, y}

  delim = (ws >> Parser.token(',') >> ws).named("delim")

  elements = (pair.sep_by(delim) << delim.optional).named("elements")

  hash_start = (Parser.token('{') >> ws).named("start")
  hash_end   = (ws >> Parser.token('}')).named("end")

  hash = parser_chain Char, Hash(Int32, Int32), "hash",
    {_,  hash_start},
    {es, elements.recover([] of {Int32, Int32})},
    {_,  hash_end},
    pure: es.to_h

  it "can parse an empty hash" do
    empty = {} of Int32 => Int32

    {"{}", "{    }", "{  \t\n\r}"}.each do |s|
      result = hash.parse(Tokens.from_string(s))
      result.value.should eq(empty)
      result.tokens.empty?.should be_true
    end
  end

  it "does not accept trailing commas in empty hashes" do
    {"{,}", "{   ,}", "{,   }",  "{  ,  }"}.each do |s|
      expect_raises(ParserFail) { hash.parse(Tokens.from_string(s)) }
    end
  end

  it "can parse hashes with one entry" do
    expected = {2_i32 => -1_i32}
    {
      "{2=>-1}",
      "{2=>-1,}",
      "{2  =>-1  ,}",
      "{   2  =>  -1  ,   }",
    }.each do |s|
      result = hash.parse(Tokens.from_string(s))
      result.value.should eq(expected)
      result.tokens.empty?.should be_true
    end
  end

  it "can parse hashes with many entries" do
    expected = {
      -2_i32 => 1_i32,
      3_i32  => -45_i32,
      -6_i32 => -7_i32,
      8_i32  => 90_i32,
    }
    {
      "{-2=>1,3=>-45,-6=>-7,8=>90}",
      "{ -2=> 1,3 => -45,-6  =>-7,8  =>  90,}",
    }.each do |s|
      result = hash.parse(Tokens.from_string(s))
      result.value.should eq(expected)
      result.tokens.empty?.should be_true
    end
  end
end