koi-reference-parser 0.0.2 → 0.0.3
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/README.rdoc +4 -0
- data/VERSION +1 -1
- data/lib/parser/koi-reference-parser.treetop +58 -45
- data/lib/parser/parser.rb +2 -17
- data/lib/parser/syntax_nodes.rb +0 -9
- data/test/{parser/functional → functional}/function_call_as_argument.rb +1 -1
- data/test/{parser/functional → functional}/simple_program_test.rb +1 -1
- data/test/helpers/assert_assigns.rb +9 -0
- data/test/helpers/assert_assigns_expression.rb +10 -0
- data/test/helpers/assert_expression.rb +11 -0
- data/test/helpers/assert_identifier.rb +6 -0
- data/test/test_helper.rb +1 -0
- data/test/unit/assignment/assignment_of_hash_value_test.rb +19 -0
- data/test/{parser/unit/hash_accessor_test.rb → unit/assignment/assignment_to_hash_test.rb} +2 -14
- data/test/unit/assignment/boolean_assignment_test.rb +17 -0
- data/test/unit/assignment/float_assignment_test.rb +22 -0
- data/test/unit/assignment/function_call_assignment_test.rb +12 -0
- data/test/unit/assignment/function_definition_test.rb +12 -0
- data/test/unit/assignment/hash_literal_assignment_test.rb +27 -0
- data/test/unit/assignment/integer_assignment_test.rb +22 -0
- data/test/unit/assignment/nil_assignment_test.rb +12 -0
- data/test/unit/assignment/string_assignment_test.rb +17 -0
- data/test/unit/expressions/addition_expression_test.rb +27 -0
- data/test/{parser/unit → unit/expressions}/compound_expression_test.rb +0 -0
- data/test/unit/expressions/division_expression_test.rb +27 -0
- data/test/unit/expressions/equality_expression_test.rb +27 -0
- data/test/unit/expressions/greater_than_expression_test.rb +27 -0
- data/test/unit/expressions/inequality_expression_test.rb +27 -0
- data/test/unit/expressions/less_than_expression_test.rb +27 -0
- data/test/unit/expressions/multiplication_expression_test.rb +27 -0
- data/test/unit/expressions/subtraction_expression_test.rb +27 -0
- data/test/{parser/unit → unit/flow_control}/if_test.rb +0 -0
- data/test/{parser/unit → unit/flow_control}/unless_test.rb +0 -0
- data/test/{parser/unit → unit/functions}/function_call_test.rb +0 -0
- data/test/{parser/unit → unit/functions}/function_definition_test.rb +0 -0
- data/test/unit/identifier_test.rb +37 -0
- data/test/{parser/unit → unit}/statement_test.rb +1 -1
- data/test/{parser/unit → unit}/syntax_node_to_hash_test.rb +1 -1
- metadata +67 -29
- data/test/parser/unit/assignment_test.rb +0 -115
- data/test/parser/unit/identifier_test.rb +0 -55
- data/test/parser/unit/simple_expression_test.rb +0 -212
data/README.rdoc
CHANGED
@@ -21,6 +21,7 @@ And turns it into an {Abstract Syntax Tree (AST)}[http://en.wikipedia.org/wiki/A
|
|
21
21
|
<AdditionOperator "+">
|
22
22
|
<IntegerLiteral "2">
|
23
23
|
|
24
|
+
The AST is also available in a far more portable format based on nested hashes by calling the to_hash method on the root AST node.
|
24
25
|
|
25
26
|
=== Installation
|
26
27
|
|
@@ -36,6 +37,9 @@ This parser is normally installed as part of Koi's default toolchain. However if
|
|
36
37
|
include KoiReferenceParser
|
37
38
|
|
38
39
|
ast = Parser.parse( program_text )
|
40
|
+
|
41
|
+
# Get the AST as a portable nested hash
|
42
|
+
ast_hash = ast.to_hash
|
39
43
|
|
40
44
|
=== Author & Credits
|
41
45
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
@@ -1,5 +1,14 @@
|
|
1
|
+
# This file is a Parsing Expression Grammar (PEG) for the Koi
|
2
|
+
# programming language. It is interpreted by the PEG engine Treetop.
|
3
|
+
|
4
|
+
# More info on PEGs: http://en.wikipedia.org/wiki/Parsing_expression_grammar
|
5
|
+
# More info on Treetop: http://treetop.rubyforge.org/
|
6
|
+
|
1
7
|
grammar KoiReferenceParser
|
2
8
|
|
9
|
+
##################
|
10
|
+
# Program structure
|
11
|
+
|
3
12
|
rule block
|
4
13
|
statement+ <Block>
|
5
14
|
end
|
@@ -8,6 +17,9 @@ grammar KoiReferenceParser
|
|
8
17
|
space? ( hash_assignment / assignment / if / unless / function_call ) ';'? space? <Statement>
|
9
18
|
end
|
10
19
|
|
20
|
+
##################
|
21
|
+
# Literals
|
22
|
+
|
11
23
|
rule nil
|
12
24
|
"nil" <NilLiteral>
|
13
25
|
end
|
@@ -36,6 +48,24 @@ grammar KoiReferenceParser
|
|
36
48
|
'$'? [a-zA-Z] [a-zA-Z0-9_]* <Identifier>
|
37
49
|
end
|
38
50
|
|
51
|
+
##################
|
52
|
+
# Hash literals
|
53
|
+
|
54
|
+
rule hash
|
55
|
+
'{' key_value_list? '}' <HashLiteral>
|
56
|
+
end
|
57
|
+
|
58
|
+
rule key_value_list
|
59
|
+
key_value+ <KeyValueList>
|
60
|
+
end
|
61
|
+
|
62
|
+
rule key_value
|
63
|
+
space? expression space? '=>' space? expression space? ','? <KeyValue>
|
64
|
+
end
|
65
|
+
|
66
|
+
##################
|
67
|
+
# Assignment
|
68
|
+
|
39
69
|
rule hash_assignment
|
40
70
|
identifier hash_accessor_list space? assignment_operator space? ( hash / function_definition / expression ) <HashAssignment>
|
41
71
|
end
|
@@ -70,18 +100,15 @@ grammar KoiReferenceParser
|
|
70
100
|
'function(' space? identifier space? ')'
|
71
101
|
block
|
72
102
|
space? 'end' <FunctionDefinition>
|
73
|
-
end
|
74
|
-
|
103
|
+
end
|
104
|
+
|
75
105
|
##################
|
76
|
-
#
|
106
|
+
# Hash component access
|
77
107
|
|
78
|
-
rule
|
79
|
-
|
108
|
+
rule hash_access
|
109
|
+
identifier hash_accessor_list <HashAccess>
|
80
110
|
end
|
81
111
|
|
82
|
-
##################
|
83
|
-
# Hashes
|
84
|
-
|
85
112
|
rule hash_accessor_list
|
86
113
|
hash_accessor+ <HashAccessorList>
|
87
114
|
end
|
@@ -89,26 +116,6 @@ grammar KoiReferenceParser
|
|
89
116
|
rule hash_accessor
|
90
117
|
'[' expression ']' <HashAccessor>
|
91
118
|
end
|
92
|
-
|
93
|
-
rule hash
|
94
|
-
'{' key_value_list? '}' <HashLiteral>
|
95
|
-
end
|
96
|
-
|
97
|
-
rule key_value_list
|
98
|
-
key_value+ <KeyValueList>
|
99
|
-
end
|
100
|
-
|
101
|
-
rule key_value
|
102
|
-
space? expression space? '=>' space? expression space? ','? <KeyValue>
|
103
|
-
end
|
104
|
-
|
105
|
-
rule key
|
106
|
-
space? expression space? <Key>
|
107
|
-
end
|
108
|
-
|
109
|
-
rule value
|
110
|
-
space? expression space? <Value>
|
111
|
-
end
|
112
119
|
|
113
120
|
##################
|
114
121
|
# Expressions
|
@@ -117,12 +124,8 @@ grammar KoiReferenceParser
|
|
117
124
|
space? (hash_access / comparative / additive) <Expression>
|
118
125
|
end
|
119
126
|
|
120
|
-
rule hash_access
|
121
|
-
identifier hash_accessor_list <HashAccess>
|
122
|
-
end
|
123
|
-
|
124
127
|
rule comparative
|
125
|
-
additive space?
|
128
|
+
additive space? comparative_operator space? additive <ComparativeExpression>
|
126
129
|
end
|
127
130
|
|
128
131
|
rule additive
|
@@ -130,12 +133,6 @@ grammar KoiReferenceParser
|
|
130
133
|
/
|
131
134
|
multitive
|
132
135
|
end
|
133
|
-
|
134
|
-
rule additive_operator
|
135
|
-
addition_operator
|
136
|
-
/
|
137
|
-
subtraction_operator
|
138
|
-
end
|
139
136
|
|
140
137
|
rule multitive
|
141
138
|
primary space? multitive_operator space? multitive <MultitiveExpression>
|
@@ -143,17 +140,26 @@ grammar KoiReferenceParser
|
|
143
140
|
primary
|
144
141
|
end
|
145
142
|
|
146
|
-
rule multitive_operator
|
147
|
-
multiplication_operator
|
148
|
-
/
|
149
|
-
division_operator
|
150
|
-
end
|
151
|
-
|
152
143
|
rule primary
|
153
144
|
function_call / nil / false / true / identifier / float / integer / string
|
154
145
|
/
|
155
146
|
'(' space? expression space? ')' <Expression>
|
156
147
|
end
|
148
|
+
|
149
|
+
##################
|
150
|
+
# Operator sets
|
151
|
+
|
152
|
+
rule comparative_operator
|
153
|
+
equality_operator / inequality_operator / greater_than_operator / less_than_operator
|
154
|
+
end
|
155
|
+
|
156
|
+
rule additive_operator
|
157
|
+
addition_operator / subtraction_operator
|
158
|
+
end
|
159
|
+
|
160
|
+
rule multitive_operator
|
161
|
+
multiplication_operator / division_operator
|
162
|
+
end
|
157
163
|
|
158
164
|
##################
|
159
165
|
# Operators
|
@@ -193,5 +199,12 @@ grammar KoiReferenceParser
|
|
193
199
|
rule less_than_operator
|
194
200
|
'<' <LessThanOperator>
|
195
201
|
end
|
202
|
+
|
203
|
+
##################
|
204
|
+
# Whitespace
|
205
|
+
|
206
|
+
rule space
|
207
|
+
[\s]+
|
208
|
+
end
|
196
209
|
|
197
210
|
end
|
data/lib/parser/parser.rb
CHANGED
@@ -8,21 +8,12 @@ class Parser
|
|
8
8
|
tree = @@parser.parse(data)
|
9
9
|
|
10
10
|
if(tree.nil?)
|
11
|
-
|
12
|
-
error_detail = "\n\n" + data.slice(@@parser.index - 120, 80).gsub("\n", ";")
|
13
|
-
error_detail += "\n" + data.slice(@@parser.index - 40, 80).gsub("\n", ";")
|
14
|
-
error_detail += "\n" + " "*40 + "^\n"
|
15
|
-
else
|
16
|
-
error_detail = "\n\n" + data.gsub("\n", ";")
|
17
|
-
error_detail += "\n" + " " * @@parser.index + "^\n"
|
18
|
-
end
|
19
|
-
raise ParseError, "Parse error at index: #{@@parser.index}#{error_detail}"
|
11
|
+
raise ParseError, "Parse error at offset: #{@@parser.index}"
|
20
12
|
end
|
21
13
|
|
22
14
|
# clean up the tree by removing all nodes of default type 'SyntaxNode'
|
23
15
|
self.clean_tree(tree)
|
24
|
-
|
25
|
-
self.clean_whitespace(tree)
|
16
|
+
|
26
17
|
return tree
|
27
18
|
end
|
28
19
|
|
@@ -33,11 +24,5 @@ class Parser
|
|
33
24
|
root_node.elements.delete_if{|node| node.class.name == "Treetop::Runtime::SyntaxNode" }
|
34
25
|
root_node.elements.each {|node| self.clean_tree(node) }
|
35
26
|
end
|
36
|
-
|
37
|
-
def self.clean_whitespace(root_node)
|
38
|
-
return if(root_node.elements.nil?)
|
39
|
-
root_node.elements.delete_if{|node| node.class.name == "KoiReferenceParser::Whitespace" }
|
40
|
-
root_node.elements.each {|node| self.clean_whitespace(node) }
|
41
|
-
end
|
42
27
|
|
43
28
|
end
|
data/lib/parser/syntax_nodes.rb
CHANGED
@@ -57,18 +57,9 @@ module KoiReferenceParser
|
|
57
57
|
class KeyValue < Treetop::Runtime::SyntaxNode
|
58
58
|
end
|
59
59
|
|
60
|
-
class Key < Treetop::Runtime::SyntaxNode
|
61
|
-
end
|
62
|
-
|
63
|
-
class Value < Treetop::Runtime::SyntaxNode
|
64
|
-
end
|
65
|
-
|
66
60
|
class Identifier < Treetop::Runtime::SyntaxNode
|
67
61
|
end
|
68
62
|
|
69
|
-
class Whitespace < Treetop::Runtime::SyntaxNode
|
70
|
-
end
|
71
|
-
|
72
63
|
class AssignmentOperator < Treetop::Runtime::SyntaxNode
|
73
64
|
end
|
74
65
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
def assert_assigns(node_type, value, tree)
|
2
|
+
assert_kind_of Block, tree
|
3
|
+
assert_kind_of Statement, tree.elements.last
|
4
|
+
assert_kind_of Assignment, tree.elements.last.elements.last
|
5
|
+
assert_kind_of Identifier, tree.elements.last.elements.last.elements[0]
|
6
|
+
assert_kind_of AssignmentOperator, tree.elements.last.elements.last.elements[1]
|
7
|
+
assert_kind_of node_type, tree.elements.last.elements.last.elements[2]
|
8
|
+
assert_equal value, tree.elements.last.elements.last.elements[2].text_value unless(value.nil?)
|
9
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
def assert_assigns_expression(node_type, value, tree)
|
2
|
+
assert_kind_of Block, tree
|
3
|
+
assert_kind_of Statement, tree.elements.last
|
4
|
+
assert_kind_of Assignment, tree.elements.last.elements.last
|
5
|
+
assert_kind_of Identifier, tree.elements.last.elements.last.elements[0]
|
6
|
+
assert_kind_of AssignmentOperator, tree.elements.last.elements.last.elements[1]
|
7
|
+
assert_kind_of Expression, tree.elements.last.elements.last.elements[2]
|
8
|
+
assert_kind_of node_type, tree.elements.last.elements.last.elements[2].elements.first
|
9
|
+
assert_equal value, tree.elements.last.elements.last.elements[2].elements.first.text_value unless(value.nil?)
|
10
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
def assert_expression(tree, expression_type, operator)
|
2
|
+
assert_kind_of Block, tree
|
3
|
+
assert_kind_of Statement, tree.elements.first
|
4
|
+
assert_kind_of Assignment, tree.elements.first.elements.last
|
5
|
+
assert_kind_of Identifier, tree.elements.first.elements.last.elements[0]
|
6
|
+
assert_kind_of AssignmentOperator, tree.elements.first.elements.last.elements[1]
|
7
|
+
assert_kind_of Expression, tree.elements.first.elements.last.elements[2]
|
8
|
+
assert_kind_of expression_type, tree.elements.first.elements.last.elements[2].elements.first
|
9
|
+
assert_equal 3, tree.elements.first.elements.last.elements[2].elements.first.elements.size
|
10
|
+
assert_kind_of operator, tree.elements.first.elements.last.elements[2].elements.first.elements[1] unless(operator.nil?)
|
11
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -4,6 +4,7 @@ require 'test/unit'
|
|
4
4
|
require_files = []
|
5
5
|
require_files << File.join(File.dirname(__FILE__), '..', 'lib', 'koi-reference-parser.rb')
|
6
6
|
require_files.concat Dir[File.join(File.dirname(__FILE__), 'setup', '*.rb')]
|
7
|
+
require_files.concat Dir[File.join(File.dirname(__FILE__), 'helpers', '*.rb')]
|
7
8
|
|
8
9
|
require_files.each do |file|
|
9
10
|
require File.expand_path(file)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class AssignmentOfHashValueTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include KoiReferenceParser
|
6
|
+
|
7
|
+
test "assignment of hash key" do
|
8
|
+
tree = Parser.parse('test = test[1]')
|
9
|
+
assert_kind_of Block, tree
|
10
|
+
assert_kind_of Statement, tree.elements.first
|
11
|
+
assert_kind_of Assignment, tree.elements.first.elements.first
|
12
|
+
assert_kind_of Identifier, tree.elements.first.elements.first.elements[0]
|
13
|
+
assert_kind_of Expression, tree.elements.first.elements.first.elements[2]
|
14
|
+
assert_kind_of HashAccess, tree.elements.first.elements.first.elements[2].elements.first
|
15
|
+
assert_kind_of Identifier, tree.elements.first.elements.first.elements[2].elements.first.elements[0]
|
16
|
+
assert_kind_of HashAccessorList, tree.elements.first.elements.first.elements[2].elements.first.elements[1]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
|
2
2
|
|
3
|
-
class
|
3
|
+
class AssignmentToHashTest < Test::Unit::TestCase
|
4
4
|
|
5
5
|
include KoiReferenceParser
|
6
|
-
|
6
|
+
|
7
7
|
test "assignment to hash key" do
|
8
8
|
tree = Parser.parse('test[1] = 1')
|
9
9
|
assert_kind_of Block, tree
|
@@ -25,17 +25,5 @@ class HashAccessorTest < Test::Unit::TestCase
|
|
25
25
|
assert_kind_of HashAccessor, tree.elements.first.elements.first.elements[1].elements.first
|
26
26
|
assert_equal 3, tree.elements.first.elements.first.elements[1].elements.length
|
27
27
|
end
|
28
|
-
|
29
|
-
test "assignment of hash key" do
|
30
|
-
tree = Parser.parse('test = test[1]')
|
31
|
-
assert_kind_of Block, tree
|
32
|
-
assert_kind_of Statement, tree.elements.first
|
33
|
-
assert_kind_of Assignment, tree.elements.first.elements.first
|
34
|
-
assert_kind_of Identifier, tree.elements.first.elements.first.elements[0]
|
35
|
-
assert_kind_of Expression, tree.elements.first.elements.first.elements[2]
|
36
|
-
assert_kind_of HashAccess, tree.elements.first.elements.first.elements[2].elements.first
|
37
|
-
assert_kind_of Identifier, tree.elements.first.elements.first.elements[2].elements.first.elements[0]
|
38
|
-
assert_kind_of HashAccessorList, tree.elements.first.elements.first.elements[2].elements.first.elements[1]
|
39
|
-
end
|
40
28
|
|
41
29
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class BooleanAssignmentTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include KoiReferenceParser
|
6
|
+
|
7
|
+
test "assignment of boolean true" do
|
8
|
+
tree = Parser.parse('test = true')
|
9
|
+
assert_assigns_expression(TrueLiteral, nil, tree)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "assignment of boolean false" do
|
13
|
+
tree = Parser.parse('test = false')
|
14
|
+
assert_assigns_expression(FalseLiteral, nil, tree)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class FloatAssignmentTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include KoiReferenceParser
|
6
|
+
|
7
|
+
test "assignment of float" do
|
8
|
+
tree = Parser.parse('test = 99.0009')
|
9
|
+
assert_assigns_expression(FloatLiteral, '99.0009', tree)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "assignment of explicitly positive float" do
|
13
|
+
tree = Parser.parse('test = +99.0009')
|
14
|
+
assert_assigns_expression(FloatLiteral, '+99.0009', tree)
|
15
|
+
end
|
16
|
+
|
17
|
+
test "assignment of explicitly negative float" do
|
18
|
+
tree = Parser.parse('test = -99.0009')
|
19
|
+
assert_assigns_expression(FloatLiteral, '-99.0009', tree)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class FunctionCallAssignmentTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include KoiReferenceParser
|
6
|
+
|
7
|
+
test "assignment of result of function call" do
|
8
|
+
tree = Parser.parse('test = function(args)')
|
9
|
+
assert_assigns_expression(FunctionCall, nil, tree)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class FunctionDefinitionAssignmentTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include KoiReferenceParser
|
6
|
+
|
7
|
+
test "assignment of function definition" do
|
8
|
+
tree = Parser.parse('test = function(args) blah = 1 end')
|
9
|
+
assert_assigns(FunctionDefinition, nil, tree)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class HashLiteralAssignmentTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include KoiReferenceParser
|
6
|
+
|
7
|
+
test "assignment of empty hash literal" do
|
8
|
+
tree = Parser.parse('test = {}')
|
9
|
+
assert_assigns(HashLiteral, nil, tree)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "assignment of hash literal with single key-value pair" do
|
13
|
+
tree = Parser.parse('test = { 1 => 2 }')
|
14
|
+
assert_assigns(HashLiteral, nil, tree)
|
15
|
+
end
|
16
|
+
|
17
|
+
test "assignment of hash literal with 2 key-value pairs" do
|
18
|
+
tree = Parser.parse('test = { 1 => 2, 2 => 2 }')
|
19
|
+
assert_assigns(HashLiteral, nil, tree)
|
20
|
+
end
|
21
|
+
|
22
|
+
test "assignment of hash literal with 3 key-value pairs" do
|
23
|
+
tree = Parser.parse('test = { 1 => 2, 2 => 2, 3 => 2 }')
|
24
|
+
assert_assigns(HashLiteral, nil, tree)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|