ql 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 10d15a58c4a27d1db1d09a4932e33283a7147ae6
4
+ data.tar.gz: d95d6dd25018321d2dc96f902a00e98556757921
5
+ SHA512:
6
+ metadata.gz: 1cd9410eda7ca232dc80df50c5faa194fad22775a7ade93fce1122d6ce5cfe9cf705336878abac5e9eae50227da77f0ca157ac9d9aaf15b0a983fd66f37ffe46
7
+ data.tar.gz: 443d7f6351884cbb84672d0c775de3ff24e9ace1feaf62dc74efaf93f2958e16e7921b41b612048e2c1b580046c9a7d6e0b58a6ab676af001a31ee43195ec686
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in q.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (C) 2014 Stojan Dimitrovski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Stojan Dimitrovski
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,50 @@
1
+
2
+ Q - a simple programming language
3
+
4
+ / Q Q Q Q
5
+ Q Q
6
+ Q Q Q Q Q
7
+ Q
8
+ Q
9
+
10
+ Install the gem from RubyGems:
11
+
12
+ $ gem install ql
13
+
14
+ Then you can use the small `q' runner to run your .q files:
15
+
16
+ $ q examples/factorial.q
17
+
18
+ Example syntax:
19
+
20
+ # assignment
21
+
22
+ a <: 10;
23
+ b <: 11;
24
+
25
+ # operations
26
+
27
+ a <: 3 + 5;
28
+ a <: a = b;
29
+ a <: a < b;
30
+ a <: b > a;
31
+
32
+ # functions
33
+
34
+ # @ refers to the current function
35
+ # every function returns @ by default
36
+ # unless you assign @ another value
37
+
38
+ factorial <: (n){
39
+ if [n < 2] then [@ <: 1] else [@ <: n * @(n - 1)];
40
+ };
41
+
42
+ tenth_factorial <: factorial(10);
43
+
44
+
45
+
46
+ This language is an experiment and parts of it were presented at
47
+ MKRUG (http://ruby.mk).
48
+
49
+ This software is licensed under the MIT/X11 license and is
50
+ Copyright (C) 2014 Stojan Dimitrovski. See LICENSE for more details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/q ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'q'
4
+
5
+ Q.load false
6
+
7
+ vm = Q::VM.new
8
+
9
+ FILES = ARGV.map do |argfile|
10
+ if not File.exist? argfile
11
+ puts "File #{argfile} does not exist."
12
+ exit 1
13
+ end
14
+
15
+ File.read argfile
16
+ end
17
+
18
+ FILES.each do |file|
19
+ vm.eval file
20
+ end
@@ -0,0 +1,6 @@
1
+ factorial <: (n){
2
+ @ <: if [n < 2] then [1] else [n * @(n - 1)];
3
+ };
4
+
5
+ puts("The factorial of 10 is: ");
6
+ puts(factorial(10));
data/lib/q.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'q/vm'
2
+
3
+ module Q
4
+ def self.load debug = false
5
+ if debug
6
+ return Treetop.load "#{File.dirname __FILE__}/q"
7
+ end
8
+
9
+ return require 'q/parser'
10
+ end
11
+ end
data/lib/q.treetop ADDED
@@ -0,0 +1,334 @@
1
+ require 'q/scope'
2
+ require 'q/syntax'
3
+
4
+ grammar Q
5
+ rule statements
6
+ statements:(ws* statement:(comment / statement) ws*)* ws* {
7
+ def eval scope
8
+ statements.elements.each do |statement|
9
+ statement.statement.eval scope
10
+ end
11
+
12
+ scope['_']
13
+ end
14
+ }
15
+ end
16
+
17
+ rule statement
18
+ expression ws* ';' {
19
+ def eval scope
20
+ scope['_'] = expression.eval scope
21
+ end
22
+ }
23
+ end
24
+
25
+ rule expression
26
+ call / assignment / conditional / binomial
27
+ end
28
+
29
+ rule function
30
+ '(' arguments:(ws* identifier ws*)* ')' '{' statements '}' <Q::Syntax::Function>
31
+ end
32
+
33
+ rule assignment
34
+ destination:(self / identifier) ws* '<:' ws* expression {
35
+ def eval scope
36
+ scope['_'] = scope[destination.text_value] = expression.eval scope
37
+ end
38
+ }
39
+ end
40
+
41
+ rule call
42
+ name:(function / self / identifier) ws* '(' arguments:(ws* argument:expression ws*)* ')' {
43
+ def eval scope
44
+ scope['_'] = name.eval(scope).call(callscope(scope))
45
+ end
46
+
47
+ def callscope scope
48
+ cscope = Q::Scope.new scope
49
+
50
+ cscope.args = arguments.elements.map.each do |argument|
51
+ argument.argument.eval(scope)
52
+ end
53
+
54
+ cscope
55
+ end
56
+ }
57
+ end
58
+
59
+ rule binomial
60
+ head:monomial ws* tail:(ws* operator:binomial_operator ws* feet:monomial)*
61
+ {
62
+ def eval scope
63
+ if has_feet?
64
+ return operator.apply(scope, head, feet)
65
+ end
66
+
67
+ scope['_'] = head.eval(scope)
68
+ end
69
+
70
+ def has_feet?
71
+ not tail.nil? and not tail.elements.first.nil? and not tail.elements.first.feet.nil?
72
+ end
73
+
74
+ def feet
75
+ return nil if not has_feet?
76
+
77
+ tail.elements.first.feet
78
+ end
79
+
80
+ def operator
81
+ return nil if not has_feet?
82
+
83
+ tail.elements.first.operator
84
+ end
85
+ }
86
+ end
87
+
88
+ rule monomial
89
+ head:primary ws* tail:(ws* operator:monomial_operator ws* feet:monomial)*
90
+ {
91
+ def eval scope
92
+ if has_feet?
93
+ feet = tail.elements.first.feet
94
+ return operator.apply(scope, head, feet)
95
+ end
96
+
97
+ scope['_'] = head.eval(scope)
98
+ end
99
+
100
+ def has_feet?
101
+ not tail.nil? and not tail.elements.first.nil? and not tail.elements.first.feet.nil?
102
+ end
103
+
104
+ def operator
105
+ return nil if not has_feet?
106
+
107
+ tail.elements.first.operator
108
+ end
109
+ }
110
+ end
111
+
112
+ rule conditional
113
+ 'if' ws* '[' condition:(conditional_expression / statements) ']' ws*
114
+ 'then' ws* '[' consequence:(conditional_expression / statements) ']'
115
+ otherwise:(ws* 'else' ws* '[' consequence:(conditional_expression / statements) ']')? <Q::Syntax::Conditional>
116
+ end
117
+
118
+ rule conditional_expression
119
+ ws* expression ws* &']' {
120
+ def eval scope
121
+ expression.eval scope
122
+ end
123
+ }
124
+ end
125
+
126
+ rule primary
127
+ call / function / self / unary / value / identifier / '(' ws* expression ws* ')' {
128
+ def eval scope
129
+ scope['_'] = expression.eval(scope)
130
+ end
131
+ }
132
+ end
133
+
134
+ rule binomial_operator
135
+ minus / plus / comparison_operators
136
+ end
137
+
138
+ rule monomial_operator
139
+ slash / star
140
+ end
141
+
142
+ rule unary
143
+ negative / negation
144
+ end
145
+
146
+ rule negation
147
+ '!' ws* primary {
148
+ def eval scope
149
+ not primary.eval(scope)
150
+ end
151
+ }
152
+ end
153
+
154
+ rule negative
155
+ '-' ws* primary {
156
+ def eval scope
157
+ - primary.eval(scope)
158
+ end
159
+ }
160
+ end
161
+
162
+ rule comparison_operators
163
+ lt / lte / gt / gte / neq / eq
164
+ end
165
+
166
+ rule lt
167
+ '<' {
168
+ def apply scope, a, b
169
+ a.eval(scope) < b.eval(scope)
170
+ end
171
+ }
172
+ end
173
+
174
+ rule gt
175
+ '>' {
176
+ def apply scope, a, b
177
+ a.eval(scope) < b.eval(scope)
178
+ end
179
+ }
180
+ end
181
+
182
+ rule lte
183
+ '<=' {
184
+ def apply scope, a, b
185
+ a.eval(scope) <= b.eval(scope)
186
+ end
187
+ }
188
+ end
189
+
190
+ rule gte
191
+ '>=' {
192
+ def apply scope, a, b
193
+ a.eval(scope) >= b.eval(scope)
194
+ end
195
+ }
196
+ end
197
+
198
+ rule eq
199
+ '=' {
200
+ def apply scope, a, b
201
+ a.eval(scope) == b.eval(scope)
202
+ end
203
+ }
204
+ end
205
+
206
+ rule neq
207
+ '!=' {
208
+ def apply scope, a, b
209
+ a.eval(scope) != b.eval(scope)
210
+ end
211
+ }
212
+ end
213
+
214
+ rule plus
215
+ '+' {
216
+ def apply scope, a, b
217
+ scope['_'] = a.eval(scope) + b.eval(scope)
218
+ end
219
+ }
220
+ end
221
+
222
+ rule minus
223
+ '-' {
224
+ def apply scope, a, b
225
+ scope['_'] = a.eval(scope) - b.eval(scope)
226
+ end
227
+ }
228
+ end
229
+
230
+ rule star
231
+ '*' {
232
+ def apply scope, a, b
233
+ scope['_'] = a.eval(scope) * b.eval(scope)
234
+ end
235
+ }
236
+ end
237
+
238
+ rule slash
239
+ '/' {
240
+ def apply scope, a, b
241
+ scope['_'] = a.eval(scope) / b.eval(scope)
242
+ end
243
+ }
244
+ end
245
+
246
+ rule value
247
+ number / string / truth / lie / nil
248
+ end
249
+
250
+ rule truth
251
+ 'true' {
252
+ def eval scope
253
+ return true
254
+ end
255
+ }
256
+ end
257
+
258
+ rule lie
259
+ 'false' {
260
+ def eval scope
261
+ return false
262
+ end
263
+ }
264
+ end
265
+
266
+ rule nil
267
+ 'nil' {
268
+ def eval scope
269
+ return nil
270
+ end
271
+ }
272
+ end
273
+
274
+ rule string
275
+ single_quote_string / double_quote_string
276
+ end
277
+
278
+ rule single_quote_string
279
+ "'" content:("\\'" / (!"'" .))* "'" {
280
+ def eval scope
281
+ content.text_value.gsub '\\\'', "'"
282
+ end
283
+ }
284
+ end
285
+
286
+ rule double_quote_string
287
+ '"' content:('\"' / (!'"' .))* '"' {
288
+ def eval scope
289
+ content.text_value.gsub '\"', '"'
290
+ end
291
+ }
292
+ end
293
+
294
+ rule number
295
+ [0-9]+ point:'.'? [0-9]*
296
+ {
297
+ def eval scope
298
+ if point.empty?
299
+ return scope['_'] = text_value.to_i
300
+ end
301
+
302
+ scope['_'] = text_value.to_f
303
+ end
304
+ }
305
+ end
306
+
307
+ rule identifier
308
+ [a-zA-Z_] [a-zA-Z0-9_]* ('?' / '!')? {
309
+ def eval scope
310
+ scope['_'] = scope[text_value]
311
+ end
312
+ }
313
+ end
314
+
315
+ rule self
316
+ '@' {
317
+ def eval scope
318
+ scope.this
319
+ end
320
+ }
321
+ end
322
+
323
+ rule comment
324
+ '#' (!("\n" / "\r") .)* ("\n" / "\r")+ {
325
+ def eval scope
326
+ # NO-OP, this is a comment for crying out loud! (:
327
+ end
328
+ }
329
+ end
330
+
331
+ rule ws
332
+ ' ' / "\n" / "\r"
333
+ end
334
+ end