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.
Files changed (42) hide show
  1. data/README.rdoc +4 -0
  2. data/VERSION +1 -1
  3. data/lib/parser/koi-reference-parser.treetop +58 -45
  4. data/lib/parser/parser.rb +2 -17
  5. data/lib/parser/syntax_nodes.rb +0 -9
  6. data/test/{parser/functional → functional}/function_call_as_argument.rb +1 -1
  7. data/test/{parser/functional → functional}/simple_program_test.rb +1 -1
  8. data/test/helpers/assert_assigns.rb +9 -0
  9. data/test/helpers/assert_assigns_expression.rb +10 -0
  10. data/test/helpers/assert_expression.rb +11 -0
  11. data/test/helpers/assert_identifier.rb +6 -0
  12. data/test/test_helper.rb +1 -0
  13. data/test/unit/assignment/assignment_of_hash_value_test.rb +19 -0
  14. data/test/{parser/unit/hash_accessor_test.rb → unit/assignment/assignment_to_hash_test.rb} +2 -14
  15. data/test/unit/assignment/boolean_assignment_test.rb +17 -0
  16. data/test/unit/assignment/float_assignment_test.rb +22 -0
  17. data/test/unit/assignment/function_call_assignment_test.rb +12 -0
  18. data/test/unit/assignment/function_definition_test.rb +12 -0
  19. data/test/unit/assignment/hash_literal_assignment_test.rb +27 -0
  20. data/test/unit/assignment/integer_assignment_test.rb +22 -0
  21. data/test/unit/assignment/nil_assignment_test.rb +12 -0
  22. data/test/unit/assignment/string_assignment_test.rb +17 -0
  23. data/test/unit/expressions/addition_expression_test.rb +27 -0
  24. data/test/{parser/unit → unit/expressions}/compound_expression_test.rb +0 -0
  25. data/test/unit/expressions/division_expression_test.rb +27 -0
  26. data/test/unit/expressions/equality_expression_test.rb +27 -0
  27. data/test/unit/expressions/greater_than_expression_test.rb +27 -0
  28. data/test/unit/expressions/inequality_expression_test.rb +27 -0
  29. data/test/unit/expressions/less_than_expression_test.rb +27 -0
  30. data/test/unit/expressions/multiplication_expression_test.rb +27 -0
  31. data/test/unit/expressions/subtraction_expression_test.rb +27 -0
  32. data/test/{parser/unit → unit/flow_control}/if_test.rb +0 -0
  33. data/test/{parser/unit → unit/flow_control}/unless_test.rb +0 -0
  34. data/test/{parser/unit → unit/functions}/function_call_test.rb +0 -0
  35. data/test/{parser/unit → unit/functions}/function_definition_test.rb +0 -0
  36. data/test/unit/identifier_test.rb +37 -0
  37. data/test/{parser/unit → unit}/statement_test.rb +1 -1
  38. data/test/{parser/unit → unit}/syntax_node_to_hash_test.rb +1 -1
  39. metadata +67 -29
  40. data/test/parser/unit/assignment_test.rb +0 -115
  41. data/test/parser/unit/identifier_test.rb +0 -55
  42. data/test/parser/unit/simple_expression_test.rb +0 -212
@@ -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.2
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
- # Whitespace
106
+ # Hash component access
77
107
 
78
- rule space
79
- [\s]+ <Whitespace>
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? (equality_operator / inequality_operator / greater_than_operator / less_than_operator) space? additive <ComparativeExpression>
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
@@ -8,21 +8,12 @@ class Parser
8
8
  tree = @@parser.parse(data)
9
9
 
10
10
  if(tree.nil?)
11
- if( data.length > 80 )
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
- # clean up the tree further by removing all whitespace nodes
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
@@ -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
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
2
2
 
3
3
  class FunctionCallAsArgumentTest < Test::Unit::TestCase
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper.rb'))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
2
2
 
3
3
  class SimpleProgramTest < Test::Unit::TestCase
4
4
 
@@ -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
@@ -0,0 +1,6 @@
1
+ def assert_identifier(tree)
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.first
6
+ end
@@ -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 HashAccessorTest < Test::Unit::TestCase
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