ql 0.0.2

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