rparsec2 1.1.0

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.
@@ -0,0 +1,40 @@
1
+ require 'rparsec/misc'
2
+
3
+ module RParsec
4
+
5
+ class CodeLocator
6
+ extend DefHelper
7
+
8
+ def_readable :code
9
+
10
+ LF = ?\n
11
+
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
22
+ end
23
+ end
24
+ return line, col
25
+ end
26
+
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
34
+ end
35
+ end
36
+ return line, col
37
+ end
38
+ end
39
+
40
+ end # module
@@ -0,0 +1,106 @@
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
19
+
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
64
+
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
76
+ end
77
+ end
78
+ # Signatures[sym] = types
79
+ __intercept_method_to_check_param_types__(sym, types)
80
+ end
81
+
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)
102
+ end
103
+ end
104
+ end
105
+
106
+ end # module
@@ -0,0 +1,63 @@
1
+ module RParsec
2
+
3
+ #
4
+ # module for Monad
5
+ #
6
+ module Monad
7
+ attr_reader :this
8
+
9
+ #
10
+ # To initialize with a monad implementation and an object that obeys the monad law.
11
+ #
12
+ def initMonad(m, v)
13
+ raise ArgumentError, 'monad cannot be nil' if m.nil?
14
+ @monad = m;
15
+ @this = v;
16
+ end
17
+
18
+ #
19
+ # To create a value based on the monad impl.
20
+ #
21
+ def value v
22
+ @monad.value v
23
+ end
24
+
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
31
+
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 }
41
+ end
42
+ end
43
+
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);
52
+ end
53
+ end
54
+
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)
60
+ end
61
+ end
62
+
63
+ end # module
@@ -0,0 +1,106 @@
1
+ require 'rparsec/parser'
2
+
3
+ module RParsec
4
+
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
+ #
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.
15
+ #
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)
27
+ end
28
+ result = result.token(symbol)
29
+ @lexers[symbol] = result
30
+ @parsers[symbol] = Parsers.token(symbol, &block)
31
+ result
32
+ end
33
+ @lexer = Parsers.sum(*lexers)
34
+ end
35
+
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
44
+
45
+ alias [] parser
46
+
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
55
+
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)
68
+ end
69
+ # suites are populated with bigger suite first
70
+ to_array suites
71
+ end
72
+
73
+ class << self
74
+ private
75
+
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.
79
+
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)
83
+ end
84
+ suites << [s]
85
+ end
86
+
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
95
+ end
96
+ end
97
+ false
98
+ end
99
+
100
+ def to_array suites
101
+ suites.reverse!.flatten!
102
+ end
103
+ end
104
+ end
105
+
106
+ end # module