citrus 1.0.0 → 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.
- data/citrus.gemspec +3 -2
- data/examples/calc_sugar.rb +0 -1
- data/extras/citrus.vim +92 -0
- data/lib/citrus.rb +14 -16
- data/lib/citrus/{peg.rb → file.rb} +4 -6
- data/test/calc_peg_test.rb +5 -0
- data/test/calc_sugar_test.rb +5 -0
- data/test/calc_test.rb +5 -0
- data/test/{peg_test.rb → file_test.rb} +7 -9
- data/test/grammar_test.rb +3 -3
- data/test/match_test.rb +12 -0
- metadata +7 -6
data/citrus.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'citrus'
|
3
|
-
s.version = '1.
|
4
|
-
s.date = '2010-05-
|
3
|
+
s.version = '1.1.0'
|
4
|
+
s.date = '2010-05-18'
|
5
5
|
|
6
6
|
s.summary = 'Parsing Expressions for Ruby'
|
7
7
|
s.description = 'Parsing Expressions for Ruby'
|
@@ -13,6 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
|
14
14
|
s.files = Dir['lib/**/*.rb'] +
|
15
15
|
Dir['examples/**/*'] +
|
16
|
+
Dir['extras/**/*'] +
|
16
17
|
Dir['test/*.rb'] +
|
17
18
|
%w< citrus.gemspec Rakefile README >
|
18
19
|
|
data/examples/calc_sugar.rb
CHANGED
data/extras/citrus.vim
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
" Vim syntax file for Citrus grammars.
|
2
|
+
"
|
3
|
+
" Language: Citrus
|
4
|
+
" Author: Michael Jackson
|
5
|
+
|
6
|
+
if version < 600
|
7
|
+
syntax clear
|
8
|
+
elseif exists("b:current_syntax")
|
9
|
+
finish
|
10
|
+
endif
|
11
|
+
|
12
|
+
syn include @rubyTop syntax/ruby.vim
|
13
|
+
|
14
|
+
syn case match
|
15
|
+
|
16
|
+
syn match ctDoubleColon "::" contained
|
17
|
+
syn match ctConstant "\u\w*" contained
|
18
|
+
syn match ctVariable "\l\w*" contained
|
19
|
+
syn match ctModule "\(\(::\)\?\u\w*\)\+" contains=ctDoubleColon,ctConstant contained
|
20
|
+
|
21
|
+
" Comments
|
22
|
+
syn match ctComment "#.*" contains=@Spell
|
23
|
+
|
24
|
+
" Keywords
|
25
|
+
syn match ctKeyword "\<super\>" contained
|
26
|
+
|
27
|
+
" Terminals
|
28
|
+
syn region ctString matchgroup=ctStringDelimiter start="\"" end="\"" skip="\\\\\|\\\"" contains=@ctStringSpecial
|
29
|
+
syn region ctString matchgroup=ctStringDelimiter start="'" end="'" skip="\\\\\|\\'"
|
30
|
+
syn region ctRegexp matchgroup=ctRegexpDelimiter start="/" end="/[iomxneus]*" skip="\\\\\|\\/" contains=@ctRegexpSpecial contained display
|
31
|
+
syn region ctCharClass matchgroup=ctRegexpDelimiter start="\[" end="\]" skip="\\\\\|\\\[" contains=@ctRegexpSpecial contained display
|
32
|
+
syn match ctAnything "\." contained display
|
33
|
+
|
34
|
+
syn cluster ctStringSpecial contains=rubyStringEscape
|
35
|
+
syn cluster ctRegexpSpecial contains=rubyStringEscape,rubyRegexpSpecial,rubyRegexpEscape,rubyRegexpBrackets,rubyRegexpCharClass,rubyRegexpDot,rubyRegexpQuantifier,rubyRegexpAnchor,rubyRegexpParens,rubyRegexpComment
|
36
|
+
|
37
|
+
" Quantifiers
|
38
|
+
syn match ctQuantifier "+" contained display
|
39
|
+
syn match ctQuantifier "?" contained display
|
40
|
+
syn match ctQuantifier "\d*\*\d*" contained display
|
41
|
+
|
42
|
+
" Operators
|
43
|
+
syn match ctOperator "|" contained
|
44
|
+
syn match ctOperator "\l\w*:"me=e-1 contained
|
45
|
+
|
46
|
+
" Extensions
|
47
|
+
syn region ctRubyBlock start="{"ms=e+1 end="}"me=s-1 contains=@rubyTop contained
|
48
|
+
syn match ctTag "<\s*\(\(::\)\?\u\w*\)\+\s*>" contains=ctModule contained
|
49
|
+
|
50
|
+
" Declarations
|
51
|
+
syn match ctRequire "\<require\>" nextgroup=ctString skipwhite skipnl
|
52
|
+
syn match ctGrammar "\<grammar\>" nextgroup=ctModule skipwhite skipnl
|
53
|
+
syn match ctInclude "\<include\>" nextgroup=ctModule skipwhite skipnl contained
|
54
|
+
syn match ctRoot "\<root\>" nextgroup=ctVariable skipwhite skipnl contained
|
55
|
+
syn match ctRule "\<rule\>" nextgroup=ctVariable skipwhite skipnl contained
|
56
|
+
|
57
|
+
" Blocks
|
58
|
+
syn region ctGrammarBlock start="\<grammar\>" matchgroup=ctGrammar end="\<end\>" contains=ctComment,ctGrammar,ctInclude,ctRoot,ctRuleBlock fold
|
59
|
+
syn region ctRuleBlock start="\<rule\>" matchgroup=ctRule end="\<end\>" contains=ALLBUT,ctRequire,ctGrammar,ctInclude,ctRoot,ctConstant,ctVariable fold
|
60
|
+
|
61
|
+
" Groups
|
62
|
+
hi def link ctComment Comment
|
63
|
+
|
64
|
+
hi def link ctRequire Include
|
65
|
+
hi def link ctInclude Include
|
66
|
+
hi def link ctGrammar ctDefine
|
67
|
+
hi def link ctRoot ctDefine
|
68
|
+
hi def link ctRule ctDefine
|
69
|
+
hi def link ctDefine Define
|
70
|
+
|
71
|
+
hi def link ctConstant Type
|
72
|
+
hi def link ctVariable Function
|
73
|
+
hi def link ctKeyword Keyword
|
74
|
+
|
75
|
+
hi def link ctString ctTerminal
|
76
|
+
hi def link ctRegexp ctTerminal
|
77
|
+
hi def link ctCharClass ctTerminal
|
78
|
+
hi def link ctAnything ctTerminal
|
79
|
+
hi def link ctTerminal String
|
80
|
+
|
81
|
+
hi def link ctRegexpDelimiter ctStringDelimiter
|
82
|
+
hi def link ctStringDelimiter Delimiter
|
83
|
+
|
84
|
+
hi def link ctRegexpSpecial ctStringSpecial
|
85
|
+
hi def link ctStringSpecial Special
|
86
|
+
|
87
|
+
hi def link ctQuantifier ctOperator
|
88
|
+
hi def link ctOperator Operator
|
89
|
+
|
90
|
+
let b:current_syntax = "citrus"
|
91
|
+
|
92
|
+
" vim: nowrap:
|
data/lib/citrus.rb
CHANGED
@@ -4,29 +4,31 @@
|
|
4
4
|
#
|
5
5
|
# http://github.com/mjijackson/citrus
|
6
6
|
module Citrus
|
7
|
-
VERSION = [1,
|
7
|
+
VERSION = [1, 1, 0]
|
8
8
|
|
9
9
|
Infinity = 1.0 / 0
|
10
10
|
|
11
|
-
autoload '
|
11
|
+
autoload 'File', 'citrus/file'
|
12
12
|
|
13
13
|
# Returns the current version of Citrus as a string.
|
14
14
|
def self.version
|
15
15
|
VERSION.join('.')
|
16
16
|
end
|
17
17
|
|
18
|
+
F = ::File
|
19
|
+
|
18
20
|
# Loads the grammar from the given +file+ into the global scope using #eval.
|
19
21
|
def self.load(file)
|
20
|
-
file << '.citrus' unless
|
21
|
-
raise "Cannot find file #{file}" unless
|
22
|
-
raise "Cannot read file #{file}" unless
|
23
|
-
self.eval(
|
22
|
+
file << '.citrus' unless F.file?(file)
|
23
|
+
raise "Cannot find file #{file}" unless F.file?(file)
|
24
|
+
raise "Cannot read file #{file}" unless F.readable?(file)
|
25
|
+
self.eval(F.read(file))
|
24
26
|
end
|
25
27
|
|
26
28
|
# Evaluates the given Citrus parsing expression grammar +code+ in the global
|
27
29
|
# scope. Returns an array of any grammar modules that were created.
|
28
30
|
def self.eval(code)
|
29
|
-
file =
|
31
|
+
file = File.parse(code)
|
30
32
|
file.value
|
31
33
|
end
|
32
34
|
|
@@ -63,19 +65,15 @@ module Citrus
|
|
63
65
|
# module is in fact a grammar.
|
64
66
|
module Grammar
|
65
67
|
# Creates a new anonymous module that includes Grammar. If a +block+ is
|
66
|
-
# provided, it
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# for the rationale behind this decision.
|
70
|
-
#
|
71
|
-
# Grammars created with this method may be assigned a name by being assigned
|
72
|
-
# to some constant, e.g.:
|
68
|
+
# provided, it is +module_eval+'d in the context of the new module. Grammars
|
69
|
+
# created with this method may be assigned a name by being assigned to some
|
70
|
+
# constant, e.g.:
|
73
71
|
#
|
74
72
|
# Calc = Grammar.new {}
|
75
73
|
#
|
76
74
|
def self.new(&block)
|
77
75
|
mod = Module.new { include Grammar }
|
78
|
-
|
76
|
+
mod.module_eval(&block) if block
|
79
77
|
mod
|
80
78
|
end
|
81
79
|
|
@@ -888,7 +886,7 @@ module Citrus
|
|
888
886
|
|
889
887
|
# Checks equality by comparing this match's #text value to +obj+.
|
890
888
|
def ==(obj)
|
891
|
-
|
889
|
+
obj == text
|
892
890
|
end
|
893
891
|
|
894
892
|
alias eql? ==
|
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'citrus'
|
2
2
|
|
3
3
|
module Citrus
|
4
|
-
# A grammar for Citrus
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
module PEG
|
4
|
+
# A grammar for Citrus grammar files. This module is used in Citrus#eval to
|
5
|
+
# parse and evaluate Citrus grammars and serves as a prime example of how to
|
6
|
+
# create a complex grammar complete with semantic interpretation in pure Ruby.
|
7
|
+
module File
|
9
8
|
include Grammar
|
10
9
|
|
11
10
|
## Hierarchical syntax
|
@@ -356,7 +355,6 @@ module Citrus
|
|
356
355
|
rule :require_keyword, [ 'require', :space ]
|
357
356
|
rule :include_keyword, [ 'include', :space ]
|
358
357
|
rule :grammar_keyword, [ 'grammar', :space ]
|
359
|
-
rule :super_keyword, [ 'super', :space ]
|
360
358
|
rule :root_keyword, [ 'root', :space ]
|
361
359
|
rule :rule_keyword, [ 'rule', :space ]
|
362
360
|
rule :end_keyword, [ 'end', :space ]
|
data/test/calc_peg_test.rb
CHANGED
data/test/calc_sugar_test.rb
CHANGED
data/test/calc_test.rb
CHANGED
@@ -1,42 +1,40 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
2
|
-
require 'citrus/
|
2
|
+
require 'citrus/file'
|
3
3
|
|
4
|
-
class
|
4
|
+
class CitrusFileTest < Test::Unit::TestCase
|
5
5
|
|
6
6
|
# A shortcut for creating a grammar that includes Citrus::PEG but uses a
|
7
7
|
# different root.
|
8
8
|
def peg(root_rule)
|
9
9
|
Grammar.new {
|
10
|
-
include Citrus::
|
10
|
+
include Citrus::File
|
11
11
|
root root_rule
|
12
12
|
}
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
15
|
## File tests
|
17
16
|
|
17
|
+
F = ::File
|
18
18
|
|
19
19
|
def run_file_test(file, root)
|
20
20
|
grammar = peg(root)
|
21
|
-
code =
|
21
|
+
code = F.read(file)
|
22
22
|
match = grammar.parse(code)
|
23
23
|
assert(match)
|
24
24
|
end
|
25
25
|
|
26
26
|
%w< rule grammar >.each do |type|
|
27
|
-
Dir[
|
27
|
+
Dir[F.dirname(__FILE__) + "/_files/#{type}*.citrus"].each do |path|
|
28
28
|
module_eval(<<-RUBY.gsub(/^ /, ''), __FILE__, __LINE__ + 1)
|
29
|
-
def test_#{
|
29
|
+
def test_#{F.basename(path, '.citrus')}
|
30
30
|
run_file_test("#{path}", :#{type})
|
31
31
|
end
|
32
32
|
RUBY
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
36
|
## Hierarchical syntax
|
38
37
|
|
39
|
-
|
40
38
|
def test_rule_body
|
41
39
|
grammar = peg(:rule_body)
|
42
40
|
|
data/test/grammar_test.rb
CHANGED
@@ -3,9 +3,9 @@ require File.dirname(__FILE__) + '/helper'
|
|
3
3
|
class GrammarTest < Test::Unit::TestCase
|
4
4
|
|
5
5
|
def test_new
|
6
|
-
Grammar.new do
|
7
|
-
assert_kind_of(Module,
|
8
|
-
assert(
|
6
|
+
Grammar.new do
|
7
|
+
assert_kind_of(Module, self)
|
8
|
+
assert(include?(Grammar))
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
data/test/match_test.rb
CHANGED
@@ -49,6 +49,18 @@ class MatchTest < Test::Unit::TestCase
|
|
49
49
|
assert_equal(11, match.length)
|
50
50
|
end
|
51
51
|
|
52
|
+
def test_equality
|
53
|
+
match1 = Match.new('a')
|
54
|
+
match2 = Match.new('a')
|
55
|
+
assert(match1 == 'a')
|
56
|
+
assert(match1 == match2)
|
57
|
+
assert(match2 == match1)
|
58
|
+
|
59
|
+
match3 = Match.new('b')
|
60
|
+
assert_equal(false, match1 == match3)
|
61
|
+
assert_equal(false, match3 == match1)
|
62
|
+
end
|
63
|
+
|
52
64
|
def test_matches
|
53
65
|
match = Double.parse('123')
|
54
66
|
assert(match)
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 1.0.0
|
9
|
+
version: 1.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Michael Jackson
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-18 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -51,12 +51,13 @@ extra_rdoc_files:
|
|
51
51
|
- README
|
52
52
|
files:
|
53
53
|
- lib/citrus/debug.rb
|
54
|
-
- lib/citrus/
|
54
|
+
- lib/citrus/file.rb
|
55
55
|
- lib/citrus/sugar.rb
|
56
56
|
- lib/citrus.rb
|
57
57
|
- examples/calc.citrus
|
58
58
|
- examples/calc.rb
|
59
59
|
- examples/calc_sugar.rb
|
60
|
+
- extras/citrus.vim
|
60
61
|
- test/alias_test.rb
|
61
62
|
- test/and_predicate_test.rb
|
62
63
|
- test/calc_peg_test.rb
|
@@ -64,13 +65,13 @@ files:
|
|
64
65
|
- test/calc_test.rb
|
65
66
|
- test/choice_test.rb
|
66
67
|
- test/expression_test.rb
|
68
|
+
- test/file_test.rb
|
67
69
|
- test/fixed_width_test.rb
|
68
70
|
- test/grammar_test.rb
|
69
71
|
- test/helper.rb
|
70
72
|
- test/label_test.rb
|
71
73
|
- test/match_test.rb
|
72
74
|
- test/not_predicate_test.rb
|
73
|
-
- test/peg_test.rb
|
74
75
|
- test/repeat_test.rb
|
75
76
|
- test/rule_test.rb
|
76
77
|
- test/sequence_test.rb
|
@@ -121,12 +122,12 @@ test_files:
|
|
121
122
|
- test/calc_test.rb
|
122
123
|
- test/choice_test.rb
|
123
124
|
- test/expression_test.rb
|
125
|
+
- test/file_test.rb
|
124
126
|
- test/fixed_width_test.rb
|
125
127
|
- test/grammar_test.rb
|
126
128
|
- test/label_test.rb
|
127
129
|
- test/match_test.rb
|
128
130
|
- test/not_predicate_test.rb
|
129
|
-
- test/peg_test.rb
|
130
131
|
- test/repeat_test.rb
|
131
132
|
- test/rule_test.rb
|
132
133
|
- test/sequence_test.rb
|