koi-reference-parser 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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