rparsec2 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,40 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rparsec/misc'
2
4
 
3
5
  module RParsec
4
6
 
5
- class CodeLocator
6
- extend DefHelper
7
+ class CodeLocator # :nodoc:
8
+ extend DefHelper
7
9
 
8
- def_readable :code
10
+ def_readable :code
9
11
 
10
- LF = ?\n
12
+ LF = ?\n
11
13
 
12
- def locate(ind)
13
- return _locateEof if ind >= code.length
14
- line, col = 1, 1
15
- return line, col if ind <= 0
16
- for i in (0...ind)
17
- c = code[i]
18
- if c == LF
19
- line, col = line + 1, 1
20
- else
21
- col = col + 1
14
+ def locate(ind)
15
+ return _locateEof if ind >= code.length
16
+ line, col = 1, 1
17
+ return line, col if ind <= 0
18
+ for i in (0...ind)
19
+ c = code[i]
20
+ if c == LF
21
+ line, col = line + 1, 1
22
+ else
23
+ col = col + 1
24
+ end
22
25
  end
26
+ return line, col
23
27
  end
24
- return line, col
25
- end
26
28
 
27
- def _locateEof
28
- line, col = 1, 1
29
- code.each_byte do |c|
30
- if c == LF.ord
31
- line, col = line + 1, 1
32
- else
33
- col = col + 1
29
+ def _locateEof
30
+ line, col = 1, 1
31
+ code.each_byte do |c|
32
+ if c == LF.ord
33
+ line, col = line + 1, 1
34
+ else
35
+ col = col + 1
36
+ end
34
37
  end
38
+ return line, col
35
39
  end
36
- return line, col
37
40
  end
38
- end
39
41
 
40
42
  end # module
data/lib/rparsec/misc.rb CHANGED
@@ -1,106 +1,23 @@
1
- module RParsec
2
-
3
- #
4
- # Helpers for defining ctor.
5
- #
6
- module DefHelper
7
- def def_ctor(*vars)
8
- define_method(:initialize) do |*params|
9
- vars.each_with_index do |var, i|
10
- instance_variable_set("@" + var.to_s, params[i])
11
- end
12
- end
13
- end
14
-
15
- def def_readable(*vars)
16
- attr_reader(*vars)
17
- def_ctor(*vars)
18
- end
1
+ # frozen_string_literal: true
19
2
 
20
- def def_mutable(*vars)
21
- attr_accessor(*vars)
22
- def_ctor(*vars)
23
- end
24
- end
25
-
26
- #
27
- # To type check method parameters.
28
- #
29
- module TypeChecker
30
- private
31
-
32
- def nth n
33
- th = case n when 0 then 'st' when 1 then 'nd' else 'th' end
34
- "#{n + 1}#{th}"
35
- end
36
-
37
- public
38
-
39
- def check_arg_type expected, obj, mtd, n = 0
40
- unless obj.kind_of? expected
41
- raise ArgumentError,
42
- "#{obj.class} assigned to #{expected} for the #{nth n} argument of #{mtd}."
43
- end
44
- end
45
-
46
- def check_arg_array_type elem_type, arg, mtd, n = 0
47
- check_arg_type Array, arg, mtd, n
48
- arg.each_with_index do |x, i|
49
- unless x.kind_of? elem_type
50
- raise ArgumentError,
51
- "#{x.class} assigned to #{elem_type} for the #{nth i} element of the #{nth n} argument of #{mtd}."
52
- end
53
- end
54
- end
55
-
56
- def check_vararg_type expected, args, mtd, n = 0
57
- (n...args.length).each do |i|
58
- check_arg_type expected, args[i], mtd, i
59
- end
60
- end
61
-
62
- extend self
63
- end
3
+ module RParsec
64
4
 
65
- #
66
- # To add declarative signature support.
67
- #
68
- module Signature
69
- # Signatures = {}
70
- def def_sig sym, *types
71
- types.each_with_index do |t, i|
72
- unless t.kind_of? Class
73
- TypeChecker.check_arg_type Class, t, :def_sig, i unless t.kind_of? Array
74
- TypeChecker.check_arg_type Class, t, :def_sig, i unless t.length <= 1
75
- TypeChecker.check_arg_array_type Class, t, :def_sig, i
5
+ #
6
+ # Helpers for defining ctor.
7
+ #
8
+ module DefHelper # :nodoc:
9
+ def def_ctor(*vars)
10
+ define_method(:initialize) do |*params|
11
+ vars.each_with_index do |var, i|
12
+ instance_variable_set("@" + var.to_s, params[i])
13
+ end
76
14
  end
77
15
  end
78
- # Signatures[sym] = types
79
- __intercept_method_to_check_param_types__(sym, types)
80
- end
81
16
 
82
- private
83
-
84
- def __intercept_method_to_check_param_types__(sym, types)
85
- mtd = instance_method(sym)
86
- define_method(sym) do |*params, &block|
87
- star_type, star_ind = nil, nil
88
- types.each_with_index do |t, i|
89
- t = star_type unless star_type.nil?
90
- arg = params[i]
91
- if t.kind_of? Class
92
- TypeChecker.check_arg_type t, arg, sym, i
93
- elsif t.empty?
94
- TypeChecker.check_arg_type Array, arg, sym, i
95
- else
96
- star_type, star_ind = t[0], i
97
- break
98
- end
99
- end
100
- TypeChecker.check_vararg_type star_type, params, sym, star_ind unless star_ind.nil?
101
- mtd.bind(self).call(*params, &block)
17
+ def def_readable(*vars)
18
+ attr_reader(*vars)
19
+ def_ctor(*vars)
102
20
  end
103
21
  end
104
- end
105
22
 
106
23
  end # module
data/lib/rparsec/monad.rb CHANGED
@@ -1,63 +1,66 @@
1
- module RParsec
1
+ # frozen_string_literal: true
2
2
 
3
- #
4
- # module for Monad
5
- #
6
- module Monad
7
- attr_reader :this
3
+ module RParsec
8
4
 
9
5
  #
10
- # To initialize with a monad implementation and an object that obeys the monad law.
6
+ # module for Monad
11
7
  #
12
- def initMonad(m, v)
13
- raise ArgumentError, 'monad cannot be nil' if m.nil?
14
- @monad = m;
15
- @this = v;
16
- end
8
+ module Monad
9
+ attr_reader :this
17
10
 
18
- #
19
- # To create a value based on the monad impl.
20
- #
21
- def value v
22
- @monad.value v
23
- end
11
+ #
12
+ # To initialize with a monad implementation and an object that obeys the monad law.
13
+ #
14
+ def initMonad(m, v)
15
+ raise ArgumentError, 'monad cannot be nil' if m.nil?
16
+ @monad = m;
17
+ @this = v;
18
+ end
24
19
 
25
- #
26
- # Run the _bind_ operation on the encapsulated object following the monad law.
27
- #
28
- def bind(&binder)
29
- @monad.bind(@this, &binder)
30
- end
20
+ #
21
+ # To create a value based on the monad impl.
22
+ #
23
+ def value v
24
+ @monad.value v
25
+ end
31
26
 
32
- #
33
- # Run the _seq_ operation on the encapsulated object following the monad law.
34
- # If _seq_ is not defined by the monad impl, use _bind_ to implement.
35
- #
36
- def seq(other)
37
- if @monad.respond_to? :seq
38
- @monad.seq(other)
39
- else
40
- bind { |_x| other }
27
+ #
28
+ # Run the _bind_ operation on the encapsulated object following the monad law.
29
+ #
30
+ def bind(&binder)
31
+ @monad.bind(@this, &binder)
41
32
  end
42
- end
43
33
 
44
- #
45
- # Run the _map_ operation on the encapsulated object following the monad law.
46
- # _bind_ is used to implement.
47
- #
48
- def map(&mapper)
49
- bind do |v|
50
- result = mapper.call v;
51
- value(result);
34
+ #
35
+ # Run the _seq_ operation on the encapsulated object following the
36
+ # monad law. If +seq+ is not defined by the monad impl, use #bind
37
+ # to implement.
38
+ #
39
+ def seq(other)
40
+ if @monad.respond_to? :seq
41
+ @monad.seq(other)
42
+ else
43
+ bind { |_x| other }
44
+ end
52
45
  end
53
- end
54
46
 
55
- #
56
- # Run the _plus_ operation on the encapsulated object following the MonadPlus law.
57
- #
58
- def plus other
59
- @monad.mplus(@this, other.this)
47
+ #
48
+ # Run the _map_ operation on the encapsulated object following the
49
+ # monad law. #bind is used to implement.
50
+ #
51
+ def map(&mapper)
52
+ bind do |v|
53
+ result = mapper.call v;
54
+ value(result);
55
+ end
56
+ end
57
+
58
+ #
59
+ # Run the _plus_ operation on the encapsulated object following the MonadPlus law.
60
+ #
61
+ def plus other
62
+ @monad.mplus(@this, other.this)
63
+ end
60
64
  end
61
- end
62
65
 
63
- end # module
66
+ end # module
@@ -0,0 +1,89 @@
1
+ module RParsec
2
+ #
3
+ # This class holds information about operator precedences and
4
+ # associativities. #prefix, #postfix, #infixl, #infixr, #infixn can
5
+ # be called to register operators.
6
+ #
7
+ class OperatorTable
8
+
9
+ #
10
+ # Operator attributes.
11
+ #
12
+ attr_reader :operators # :nodoc:
13
+
14
+ #
15
+ # Re-initialize the operator table.
16
+ #
17
+ def reinit # :nodoc:
18
+ @operators = []
19
+ end
20
+
21
+ #
22
+ # To create an OperatorTable instance. If a block is given, it is
23
+ # invoked to do post-instantiation. For example:
24
+ #
25
+ # OperatorTable.new do |tbl|
26
+ # tbl.infixl(char(?+) >> Plus, 10)
27
+ # tbl.infixl(char(?-) >> Minus, 10)
28
+ # tbl.infixl(char(?*) >> Mul, 20)
29
+ # tbl.infixl(char(?/) >> Div, 20)
30
+ # tbl.prefix(char(?-) >> Neg, 50)
31
+ # end
32
+ #
33
+ def self.new
34
+ this = allocate
35
+ this.reinit
36
+ if block_given?
37
+ yield this
38
+ end
39
+ this
40
+ end
41
+
42
+ #
43
+ # Defines a prefix operator that returns a unary +Proc+ object with a precedence associated.
44
+ # Returns +self+.
45
+ #
46
+ def prefix(op, precedence)
47
+ add(:prefix, op, precedence)
48
+ end
49
+
50
+ #
51
+ # Defines a postfix operator that returns a unary +Proc+ object with a precedence associated.
52
+ # Returns +self+.
53
+ #
54
+ def postfix(op, precedence)
55
+ add(:postfix, op, precedence)
56
+ end
57
+
58
+ #
59
+ # Defines a left associative infix operator that returns a binary +Proc+ object with a precedence
60
+ # associated. Returns +self+.
61
+ #
62
+ def infixl(op, precedence)
63
+ add(:infixl, op, precedence)
64
+ end
65
+
66
+ #
67
+ # Defines a right associative infix operator that returns a binary +Proc+ object with a precedence
68
+ # associated. Returns +self+.
69
+ #
70
+ def infixr(op, precedence)
71
+ add(:infixr, op, precedence)
72
+ end
73
+
74
+ #
75
+ # Defines a non-associative infix operator that returns a binary +Proc+ object with a precedence
76
+ # associated. Returns +self+.
77
+ #
78
+ def infixn(op, precedence)
79
+ add(:infixn, op, precedence)
80
+ end
81
+
82
+ private
83
+
84
+ def add(*entry)
85
+ @operators << entry
86
+ self
87
+ end
88
+ end
89
+ end
@@ -1,106 +1,110 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rparsec/parser'
2
4
 
3
5
  module RParsec
4
6
 
5
- #
6
- # This class helps building lexer and parser for operators.
7
- # The case that one operator (++ for example) contains another operator (+)
8
- # is automatically handled so client code don't have to worry about ambiguity.
9
- #
10
- class Operators
11
7
  #
12
- # To create an instance of Operators for the given operators.
13
- # The _block_ parameter, if present, is used to convert the token text to another object
14
- # when the token is recognized during grammar parsing phase.
8
+ # This class helps building lexer and parser for operators. The
9
+ # case that one operator (<tt>++</tt> for example) contains another
10
+ # operator (<tt>+</tt>) is automatically handled so client code
11
+ # don't have to worry about ambiguity.
15
12
  #
16
- def initialize(ops, &block)
17
- @lexers = {}
18
- @parsers = {}
19
- sorted = Operators.sort(ops)
20
- lexers = sorted.map do |op|
21
- symbol = op.to_sym
22
- result = nil
23
- if op.length == 1
24
- result = Parsers.char(op)
25
- else
26
- result = Parsers.str(op)
13
+ class Operators
14
+ #
15
+ # To create an instance of Operators for the given operators. The
16
+ # +block+ parameter, if present, is used to convert the token text
17
+ # to another object when the token is recognized during grammar
18
+ # parsing phase.
19
+ #
20
+ def initialize(ops, &block)
21
+ @lexers = {}
22
+ @parsers = {}
23
+ sorted = Operators.sort(ops)
24
+ lexers = sorted.map do |op|
25
+ symbol = op.to_sym
26
+ result = nil
27
+ if op.length == 1
28
+ result = Parsers.char(op)
29
+ else
30
+ result = Parsers.str(op)
31
+ end
32
+ result = result.token(symbol)
33
+ @lexers[symbol] = result
34
+ @parsers[symbol] = Parsers.token(symbol, &block)
35
+ result
27
36
  end
28
- result = result.token(symbol)
29
- @lexers[symbol] = result
30
- @parsers[symbol] = Parsers.token(symbol, &block)
31
- result
37
+ @lexer = Parsers.sum(*lexers)
32
38
  end
33
- @lexer = Parsers.sum(*lexers)
34
- end
35
39
 
36
- #
37
- # Get the parser for the given operator.
38
- #
39
- def parser(op)
40
- result = @parsers[op.to_sym]
41
- raise ArgumentError, "parser not found for #{op}" if result.nil?
42
- result
43
- end
40
+ #
41
+ # Get the parser for the given operator.
42
+ #
43
+ def parser(op)
44
+ result = @parsers[op.to_sym]
45
+ raise ArgumentError, "parser not found for #{op}" if result.nil?
46
+ result
47
+ end
44
48
 
45
- alias [] parser
49
+ alias [] parser
46
50
 
47
- #
48
- # Get the lexer that lexes operators.
49
- # If an operator is specified, the lexer for that operator is returned.
50
- #
51
- def lexer(op = nil)
52
- return @lexer if op.nil?
53
- @lexers[op.to_sym]
54
- end
51
+ #
52
+ # Get the lexer that lexes operators.
53
+ # If an operator is specified, the lexer for that operator is returned.
54
+ #
55
+ def lexer(op = nil)
56
+ return @lexer if op.nil?
57
+ @lexers[op.to_sym]
58
+ end
55
59
 
56
- #
57
- # Sort an array of operators so that contained operator appears after containers.
58
- # When no containment exist between two operators, the shorter one takes precedence.
59
- #
60
- def self.sort(ops)
61
- #sort the array by longer-string-first.
62
- i = 0
63
- ordered = ops.sort_by { |x| [x.length, i += 1] }.reverse
64
- suites = []
65
- # loop from the longer to shorter string
66
- ordered.each do |s|
67
- populate_suites(suites, s)
60
+ #
61
+ # Sort an array of operators so that contained operator appears after containers.
62
+ # When no containment exist between two operators, the shorter one takes precedence.
63
+ #
64
+ def self.sort(ops)
65
+ #sort the array by longer-string-first.
66
+ i = 0
67
+ ordered = ops.sort_by { |x| [x.length, i += 1] }.reverse
68
+ suites = []
69
+ # loop from the longer to shorter string
70
+ ordered.each do |s|
71
+ populate_suites(suites, s)
72
+ end
73
+ # suites are populated with bigger suite first
74
+ to_array suites
68
75
  end
69
- # suites are populated with bigger suite first
70
- to_array suites
71
- end
72
76
 
73
- class << self
74
- private
77
+ class << self
78
+ private
75
79
 
76
- def populate_suites(suites, s)
77
- # populate the suites so that bigger suite first
78
- # this way we can use << operator for non-contained strings.
80
+ def populate_suites(suites, s)
81
+ # populate the suites so that bigger suite first
82
+ # this way we can use << operator for non-contained strings.
79
83
 
80
- # we need to start from bigger suite. So loop in reverse order
81
- for suite in suites
82
- return if populate_suite(suite, s)
84
+ # we need to start from bigger suite. So loop in reverse order
85
+ for suite in suites
86
+ return if populate_suite(suite, s)
87
+ end
88
+ suites << [s]
83
89
  end
84
- suites << [s]
85
- end
86
90
 
87
- def populate_suite(suite, s)
88
- # loop from the tail of the suite
89
- for i in (1..suite.length)
90
- ind = suite.length - i
91
- cur = suite[ind]
92
- if cur.start_with?(s)
93
- suite.insert(ind + 1, s) unless cur == s
94
- return true
91
+ def populate_suite(suite, s)
92
+ # loop from the tail of the suite
93
+ for i in (1..suite.length)
94
+ ind = suite.length - i
95
+ cur = suite[ind]
96
+ if cur.start_with?(s)
97
+ suite.insert(ind + 1, s) unless cur == s
98
+ return true
99
+ end
95
100
  end
101
+ false
96
102
  end
97
- false
98
- end
99
103
 
100
- def to_array suites
101
- suites.reverse!.flatten!
104
+ def to_array suites
105
+ suites.reverse!.flatten!
106
+ end
102
107
  end
103
108
  end
104
- end
105
109
 
106
110
  end # module