phaad 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +44 -0
- data/lib/phaad/cli.rb +76 -13
- data/lib/phaad/generator.rb +378 -18
- data/lib/phaad/version.rb +1 -1
- data/lib/phaad.rb +3 -0
- data/phaad.gemspec +3 -1
- data/spec/generator/array_spec.rb +54 -0
- data/spec/generator/assign_spec.rb +15 -0
- data/spec/generator/binary_spec.rb +55 -0
- data/spec/generator/class_spec.rb +45 -0
- data/spec/generator/constants_spec.rb +39 -0
- data/spec/generator/for_spec.rb +39 -0
- data/spec/generator/function_spec.rb +37 -0
- data/spec/generator/if_spec.rb +49 -0
- data/spec/generator/ivar_spec.rb +8 -0
- data/spec/generator/literal_spec.rb +13 -13
- data/spec/generator/massign_spec.rb +11 -0
- data/spec/generator/paren_spec.rb +9 -0
- data/spec/generator/return_spec.rb +8 -0
- data/spec/generator/string_spec.rb +39 -0
- data/spec/generator/ternary_spec.rb +7 -0
- data/spec/generator/unary_spec.rb +14 -0
- data/spec/generator/while_spec.rb +20 -0
- data/spec/generator/whitespace_spec.rb +101 -0
- data/spec/phaad_spec.rb +4 -0
- data/spec/spec_helper.rb +6 -0
- metadata +45 -5
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Phaad
|
2
|
+
|
3
|
+
Phaad is a little language, written in Ruby, implementing a subset of Ruby's syntax, and compiling it down to PHP.
|
4
|
+
|
5
|
+
## Status
|
6
|
+
|
7
|
+
Phaad is a work in progress. I made it to save myself from typing dollar signs, and brackets everywhere, when developing in PHP, while teaching myself a little about Lexers and Parsers.
|
8
|
+
|
9
|
+
The following features are currently implemented
|
10
|
+
|
11
|
+
- Unary operators ~, +, -, !
|
12
|
+
- Binary operators
|
13
|
+
- Arithmetic: +, -, \*, /, %, \*\* (converted to `pow`)
|
14
|
+
- Logical: &&, ||, and, or
|
15
|
+
- Bitwise: |, &, ^
|
16
|
+
- Comparison: ==, !=, >, <, >=, <=, ===
|
17
|
+
- Regex match: =~, !~ (converted to `preg_match`)
|
18
|
+
- Assigning variables, both single and multiple at once (`a, b = 1, 2` => `$a = 1;\n$b=2;`)
|
19
|
+
- if, unless, while, and until statements, both in the long and one line form of Ruby
|
20
|
+
- Function definitions
|
21
|
+
- Arrays, both linear and associative
|
22
|
+
|
23
|
+
## Getting Started
|
24
|
+
|
25
|
+
### Installing
|
26
|
+
|
27
|
+
It's best to install the latest revision from the repository.
|
28
|
+
|
29
|
+
git clone https://github.com/utkarshkukreti/phaad.git
|
30
|
+
cd phaad
|
31
|
+
bundle install
|
32
|
+
rake spec # optional
|
33
|
+
rake install
|
34
|
+
|
35
|
+
Installing the gem will provide you with a `phaad` command. Invoking it without any parameters brings up an interactive REPL, similar to IRB. You can type in code, and get the generated PHP code back instantly.
|
36
|
+
|
37
|
+
## Examples
|
38
|
+
|
39
|
+
It's best to checkout the [spec](https://github.com/utkarshkukreti/phaad/tree/master/spec) directory for a list of features with examples for now.
|
40
|
+
|
41
|
+
## License
|
42
|
+
|
43
|
+
MIT License. (c) 2011 Utkarsh Kukreti.
|
44
|
+
|
data/lib/phaad/cli.rb
CHANGED
@@ -1,24 +1,87 @@
|
|
1
1
|
module Phaad
|
2
2
|
class CLI
|
3
3
|
def initialize(argv)
|
4
|
-
|
4
|
+
@options = Slop.parse! argv, :help => true do
|
5
|
+
banner "Usage: phaad [options] [file]"
|
6
|
+
on :c, :compile, "Compile to PHP, and save as .php files"
|
7
|
+
on :i, :interactive, "Run an interactive Phaad REPL"
|
8
|
+
on :s, :stdio, "Fetch, compile, and print a Phaad script over stdio"
|
9
|
+
on :e, :eval, "Compile a string from command line", true
|
10
|
+
on :w, :watch, "Watch a Phaad file for changes, and autocompile"
|
11
|
+
on :v, :version, "Print Phaad version" do
|
12
|
+
puts Phaad::VERSION
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if @options.interactive?
|
18
|
+
repl
|
19
|
+
elsif @options.eval?
|
20
|
+
puts compile(@options[:eval])
|
21
|
+
elsif @options.stdio?
|
22
|
+
puts "<?php\n"
|
23
|
+
puts compile(STDIN.readlines.join("\n"))
|
24
|
+
elsif @options.compile?
|
25
|
+
input_file = argv.shift
|
26
|
+
output_file = input_file.sub(/\..*?$/, '.php')
|
27
|
+
File.open(output_file, 'w') do |f|
|
28
|
+
f << "<?php\n"
|
29
|
+
f << compile(File.read(input_file))
|
30
|
+
end
|
31
|
+
elsif @options.watch?
|
32
|
+
require 'fssm'
|
33
|
+
|
34
|
+
input_file = argv.shift
|
35
|
+
output_file = input_file.sub(/\..*?$/, '.php')
|
36
|
+
FSSM.monitor(File.dirname(input_file), File.basename(input_file)) do
|
37
|
+
update do
|
38
|
+
puts ">>> Detected changes in #{input_file}"
|
39
|
+
File.open(output_file, 'w') do |f|
|
40
|
+
f << "<?php\n"
|
41
|
+
f << Phaad::Generator.new(File.read(input_file)).emitted
|
42
|
+
end
|
43
|
+
puts ">>> Compiled!"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
repl
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def compile(input)
|
52
|
+
Phaad::Generator.new(input).emitted
|
5
53
|
end
|
6
54
|
|
7
|
-
##
|
8
|
-
# A very primitive repl. Only handles one lines.
|
9
55
|
def repl
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
56
|
+
require 'readline'
|
57
|
+
|
58
|
+
puts "Type exit or press Ctrl-D to exit."
|
59
|
+
lines = ""
|
60
|
+
loop do
|
61
|
+
prompt = lines.size == 0 ? '> ' : '>> '
|
62
|
+
line = Readline::readline(prompt)
|
63
|
+
|
64
|
+
exit if line.nil? || line == "exit" && lines.size == 0
|
65
|
+
|
66
|
+
lines << line + "\n"
|
67
|
+
Readline::HISTORY.push line
|
68
|
+
|
69
|
+
if valid_expression?(lines)
|
70
|
+
begin
|
71
|
+
puts Phaad::Generator.new(lines).emitted
|
72
|
+
rescue Exception => e
|
73
|
+
puts e
|
74
|
+
p e.message
|
75
|
+
puts e.backtrace
|
76
|
+
ensure
|
77
|
+
lines = ""
|
78
|
+
end
|
19
79
|
end
|
20
|
-
print "> "
|
21
80
|
end
|
22
81
|
end
|
82
|
+
|
83
|
+
def valid_expression?(lines)
|
84
|
+
!!Ripper.sexp(lines)
|
85
|
+
end
|
23
86
|
end
|
24
87
|
end
|
data/lib/phaad/generator.rb
CHANGED
@@ -14,44 +14,404 @@ module Phaad
|
|
14
14
|
end
|
15
15
|
|
16
16
|
@emitted = ""
|
17
|
-
@
|
17
|
+
@indent_level = 0
|
18
|
+
@indent_with = " "
|
19
|
+
process_statements @sexp.last, :indent => false
|
20
|
+
@emitted.chomp!
|
18
21
|
end
|
19
22
|
|
20
|
-
def
|
21
|
-
|
23
|
+
def process_statements(array, options = {})
|
24
|
+
indent unless options[:indent] == false
|
25
|
+
array.each do |sexp|
|
26
|
+
process(sexp)
|
27
|
+
should_not_be = [ [:bodystmt, [[:void_stmt]], nil, nil, nil] ]
|
28
|
+
first_should_not_be = [:void_stmt, :def, :bodystmt, :if, :else, :elsif,
|
29
|
+
:unless, :while, :until, :while_mod, :until_mod, :if_mod, :unless_mod,
|
30
|
+
:massign, :class, :for]
|
31
|
+
emit ";\n" if !should_not_be.include?(sexp) && !first_should_not_be.include?(sexp.first)
|
32
|
+
end
|
33
|
+
outdent unless options[:indent] == false
|
34
|
+
end
|
35
|
+
|
36
|
+
def indent
|
37
|
+
@indent_level += 1
|
38
|
+
end
|
39
|
+
|
40
|
+
def outdent
|
41
|
+
@indent_level -= 1
|
42
|
+
end
|
43
|
+
|
44
|
+
def emit(*strings)
|
45
|
+
strings.each do |string|
|
46
|
+
@emitted << @indent_with * @indent_level if @emitted[-1] == "\n"
|
47
|
+
@emitted << string
|
48
|
+
end
|
22
49
|
end
|
23
50
|
|
24
51
|
def process(sexp)
|
25
52
|
case sexp.first
|
53
|
+
when :void_stmt
|
26
54
|
when :@int, :@float
|
27
55
|
emit sexp[1]
|
28
56
|
when :@tstring_content
|
29
|
-
"\"#{sexp[1]}\""
|
57
|
+
emit "\"#{sexp[1].gsub('"', '\"')}\""
|
30
58
|
when :string_content
|
31
|
-
|
59
|
+
if sexp.size > 1
|
60
|
+
sexp[1..-1].each_with_index do |exp, i|
|
61
|
+
unless exp[0] == :string_embexpr && exp[1][0][0] == :void_stmt
|
62
|
+
process exp
|
63
|
+
emit " . " if i < sexp.size - 2
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
emit '""'
|
68
|
+
end
|
32
69
|
when :string_literal
|
33
|
-
|
70
|
+
process(sexp[1])
|
71
|
+
when :string_embexpr
|
72
|
+
process sexp[1][0]
|
34
73
|
when :regexp_literal
|
35
|
-
emit "
|
74
|
+
emit '"/'
|
75
|
+
emit sexp[1][0][1]
|
76
|
+
process sexp[2]
|
77
|
+
emit '"'
|
36
78
|
when :@regexp_end
|
37
|
-
sexp[1]
|
79
|
+
emit sexp[1]
|
38
80
|
when :symbol_literal
|
39
81
|
emit sexp[1][1][1].inspect
|
40
82
|
when :dyna_symbol
|
41
|
-
|
83
|
+
process(sexp[1][0])
|
84
|
+
when :assign
|
85
|
+
process(sexp[1])
|
86
|
+
emit " = "
|
87
|
+
process(sexp[2])
|
88
|
+
when :massign
|
89
|
+
lhs = sexp[1]
|
90
|
+
rhs = sexp[2]
|
91
|
+
|
92
|
+
# hack, no idea why is the sexp like this.
|
93
|
+
rhs.shift if rhs.first == :mrhs_new_from_args
|
94
|
+
rhs = rhs[0] + [rhs[1]]
|
95
|
+
unless lhs.size == rhs.size
|
96
|
+
raise NotImplementedError, sexp.inspect
|
97
|
+
end
|
98
|
+
|
99
|
+
lhs.zip(rhs).each do |l, r|
|
100
|
+
process l
|
101
|
+
emit " = "
|
102
|
+
process r
|
103
|
+
emit ";\n"
|
104
|
+
end
|
105
|
+
when :return
|
106
|
+
emit "return "
|
107
|
+
process sexp[1]
|
108
|
+
when :var_field
|
109
|
+
process(sexp[1])
|
110
|
+
when :@ident
|
111
|
+
no_dollar = ["__NAMESPACE__", "__DIR__", "__METHOD__", "__CLASS__", "__FUNCTION__"]
|
112
|
+
emit "$" unless no_dollar.include?(sexp[1])
|
113
|
+
emit sexp[1]
|
114
|
+
when :@ivar
|
115
|
+
emit "$this->"
|
116
|
+
emit sexp[1][1..-1]
|
117
|
+
when :@const
|
118
|
+
emit sexp[1]
|
119
|
+
when :method_add_arg
|
120
|
+
if sexp[1][0] == :fcall && sexp[1][1][0] == :@ident
|
121
|
+
emit sexp[1][1][1]
|
122
|
+
emit "("
|
123
|
+
process sexp[2][1] if sexp[2][1]
|
124
|
+
emit ")"
|
125
|
+
elsif sexp[1][0] == :call
|
126
|
+
process sexp[1]
|
127
|
+
emit "("
|
128
|
+
process sexp[2][1] if sexp[2][1]
|
129
|
+
emit ")"
|
130
|
+
else
|
131
|
+
raise NotImplementedError, sexp.inspect
|
132
|
+
end
|
133
|
+
when :ifop
|
134
|
+
process sexp[1]
|
135
|
+
emit " ? "
|
136
|
+
process sexp[2]
|
137
|
+
emit " : "
|
138
|
+
process sexp[3]
|
139
|
+
when :command
|
140
|
+
if sexp[1][0] == :@ident
|
141
|
+
no_brackets = %w{global echo}
|
142
|
+
emit sexp[1][1]
|
143
|
+
emit no_brackets.include?(sexp[1][1]) ? " " : "("
|
144
|
+
if sexp[2][0] == :args_add_block
|
145
|
+
process sexp[2]
|
146
|
+
else
|
147
|
+
sexp[2].each(&method(:process))
|
148
|
+
end
|
149
|
+
emit ")" unless no_brackets.include?(sexp[1][1])
|
150
|
+
else
|
151
|
+
raise NotImplementedError, sexp.inspect
|
152
|
+
end
|
153
|
+
when :args_add_block
|
154
|
+
sexp[1].each do |s|
|
155
|
+
process s
|
156
|
+
emit ", " unless s == sexp[1].last
|
157
|
+
end
|
158
|
+
when :call
|
159
|
+
process sexp[1]
|
160
|
+
emit "->"
|
161
|
+
emit sexp[3][1]
|
162
|
+
when :command_call
|
163
|
+
if sexp[1][0] == :var_ref && sexp[1][1][0] == :@ident && sexp[2] == :"." &&
|
164
|
+
sexp[3][0] == :@ident && sexp[4][0] == :args_add_block
|
165
|
+
process sexp[1]
|
166
|
+
emit "->"
|
167
|
+
emit sexp[3][1]
|
168
|
+
emit "("
|
169
|
+
process sexp[4]
|
170
|
+
emit ")"
|
171
|
+
else
|
172
|
+
raise NotImplementedError, sexp.inspect
|
173
|
+
end
|
174
|
+
when :if, :elsif, :unless
|
175
|
+
if sexp.first == :if
|
176
|
+
emit "if("
|
177
|
+
elsif sexp.first == :unless
|
178
|
+
emit "if(!("
|
179
|
+
else
|
180
|
+
emit "elseif("
|
181
|
+
end
|
182
|
+
process sexp[1]
|
183
|
+
emit ")" if sexp.first == :unless
|
184
|
+
emit ") {\n"
|
185
|
+
process_statements(sexp[2])
|
186
|
+
emit "}"
|
187
|
+
if sexp[3]
|
188
|
+
emit " "
|
189
|
+
process sexp[3]
|
190
|
+
else
|
191
|
+
emit "\n"
|
192
|
+
end
|
193
|
+
when :else
|
194
|
+
emit "else {\n"
|
195
|
+
process_statements(sexp[1]) if sexp[1]
|
196
|
+
emit "}\n"
|
197
|
+
process sexp[3] if sexp[3]
|
198
|
+
when :if_mod, :unless_mod
|
199
|
+
emit "if("
|
200
|
+
emit "!(" if sexp.first == :unless_mod
|
201
|
+
process sexp[1]
|
202
|
+
emit ")" if sexp.first == :unless_mod
|
203
|
+
emit ") {\n"
|
204
|
+
process_statements [sexp[2]]
|
205
|
+
emit "}\n"
|
206
|
+
when :while, :until
|
207
|
+
emit "while("
|
208
|
+
emit "!(" if sexp.first == :until
|
209
|
+
process sexp[1]
|
210
|
+
emit ")" if sexp.first == :until
|
211
|
+
emit ") {\n"
|
212
|
+
process_statements sexp[2]
|
213
|
+
emit "}\n"
|
214
|
+
when :while_mod, :until_mod
|
215
|
+
emit "while("
|
216
|
+
emit "!(" if sexp.first == :until_mod
|
217
|
+
process sexp[1]
|
218
|
+
emit ")" if sexp.first == :until_mod
|
219
|
+
emit ") {\n"
|
220
|
+
process_statements [sexp[2]]
|
221
|
+
emit "}\n"
|
222
|
+
when :for
|
223
|
+
if !sexp[1][0].is_a?(Array) && sexp[2][0] == :dot2 || sexp[2][0] == :dot3
|
224
|
+
emit "for("
|
225
|
+
process sexp[1]
|
226
|
+
emit " = "
|
227
|
+
process sexp[2][1]
|
228
|
+
emit "; "
|
229
|
+
process sexp[1]
|
230
|
+
emit sexp[2][0] == :dot2 ? " <= " : " < "
|
231
|
+
process sexp[2][2]
|
232
|
+
emit "; "
|
233
|
+
process sexp[1]
|
234
|
+
emit "++"
|
235
|
+
else
|
236
|
+
emit "foreach("
|
237
|
+
process sexp[2]
|
238
|
+
emit " as "
|
239
|
+
if !sexp[1][0].is_a?(Array)
|
240
|
+
process sexp[1]
|
241
|
+
elsif sexp[1][0].is_a?(Array) && sexp[1].size == 2
|
242
|
+
process sexp[1][0]
|
243
|
+
emit " => "
|
244
|
+
process sexp[1][1]
|
245
|
+
else
|
246
|
+
raise NotImplementedError, sexp.inspect
|
247
|
+
end
|
248
|
+
end
|
249
|
+
emit ") {\n"
|
250
|
+
process_statements sexp[3]
|
251
|
+
emit "}\n"
|
252
|
+
when :def
|
253
|
+
raise NotImplementedError, sexp.inspect unless sexp[1][0] == :@ident
|
254
|
+
emit "function "
|
255
|
+
emit sexp[1][1]
|
256
|
+
emit "("
|
257
|
+
if sexp[2][0] == :params
|
258
|
+
process sexp[2] # params
|
259
|
+
elsif sexp[2][0] == :paren && sexp[2][1][0] == :params
|
260
|
+
process sexp[2][1]
|
261
|
+
else
|
262
|
+
raise NotImplementedError, sexp.inspect
|
263
|
+
end
|
264
|
+
emit ") {\n"
|
265
|
+
process_statements [sexp[3]]
|
266
|
+
emit "}\n"
|
267
|
+
when :class
|
268
|
+
if sexp[1][1][0] != :@const || (sexp[2] && sexp[2][1][0] != :@const)
|
269
|
+
raise NotImplementedError, sexp.inspect
|
270
|
+
end
|
271
|
+
emit "class "
|
272
|
+
emit sexp[1][1][1]
|
273
|
+
emit " extends #{sexp[2][1][1]}" if sexp[2]
|
274
|
+
emit " {\n"
|
275
|
+
process_statements [sexp[3]]
|
276
|
+
emit "}\n"
|
277
|
+
when :params
|
278
|
+
first = true
|
279
|
+
if sexp[1]
|
280
|
+
sexp[1].each do |param|
|
281
|
+
emit ", " unless first
|
282
|
+
first = false
|
283
|
+
|
284
|
+
process param
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
if sexp[2]
|
289
|
+
sexp[2].each do |param|
|
290
|
+
emit ", " unless first
|
291
|
+
first = false
|
292
|
+
|
293
|
+
process param[0]
|
294
|
+
emit " = "
|
295
|
+
process param[1]
|
296
|
+
end
|
297
|
+
end
|
298
|
+
when :array, :hash
|
299
|
+
emit "array("
|
300
|
+
if sexp[1]
|
301
|
+
if sexp[1][0] == :assoclist_from_args
|
302
|
+
process sexp[1]
|
303
|
+
else
|
304
|
+
sexp[1].each_with_index do |param, i|
|
305
|
+
process param
|
306
|
+
emit ", " if i < sexp[1].size - 1
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
emit ")"
|
311
|
+
when :assoclist_from_args
|
312
|
+
sexp[1].each_with_index do |param, i|
|
313
|
+
process param
|
314
|
+
emit ", " if i < sexp[1].size - 1
|
315
|
+
end
|
316
|
+
when :assoc_new
|
317
|
+
process sexp[1]
|
318
|
+
emit " => "
|
319
|
+
process sexp[2]
|
320
|
+
when :bodystmt
|
321
|
+
process_statements(sexp[1], :indent => false)
|
322
|
+
# skip rescue and ensure
|
323
|
+
when :paren
|
324
|
+
emit "("
|
325
|
+
if sexp[1].size == 1
|
326
|
+
process sexp[1][0]
|
327
|
+
else
|
328
|
+
raise NotImplementedError, sexp.inspect
|
329
|
+
end
|
330
|
+
emit ")"
|
331
|
+
when :aref_field
|
332
|
+
process sexp[1]
|
333
|
+
emit "["
|
334
|
+
process sexp[2] if sexp[2]
|
335
|
+
emit "]"
|
336
|
+
when :aref
|
337
|
+
process sexp[1]
|
338
|
+
emit "["
|
339
|
+
if sexp[2][1].size == 1
|
340
|
+
process sexp[2] if sexp[2][1][0]
|
341
|
+
else
|
342
|
+
raise NotImplementedError, sexp.inspect
|
343
|
+
end
|
344
|
+
emit "]"
|
345
|
+
when :unary
|
346
|
+
case sexp[1]
|
347
|
+
when :+@, :-@, :~, :'!'
|
348
|
+
emit sexp[1].to_s[0]
|
349
|
+
process sexp[2]
|
350
|
+
else
|
351
|
+
raise NotImplementedError, sexp.inspect
|
352
|
+
end
|
353
|
+
when :binary
|
354
|
+
case sexp[2]
|
355
|
+
when :+, :-, :*, :/, :%, :|, :&, :^, :'&&', :'||', :==, :'!=', :>, :<,
|
356
|
+
:>=, :<=, :===
|
357
|
+
process(sexp[1])
|
358
|
+
emit " #{sexp[2]} "
|
359
|
+
process(sexp[3])
|
360
|
+
when :and
|
361
|
+
process(sexp[1])
|
362
|
+
emit " && "
|
363
|
+
process(sexp[3])
|
364
|
+
when :or
|
365
|
+
process(sexp[1])
|
366
|
+
emit " || "
|
367
|
+
process(sexp[3])
|
368
|
+
when :<<
|
369
|
+
process(sexp[1])
|
370
|
+
emit " . "
|
371
|
+
process(sexp[3])
|
372
|
+
when :**
|
373
|
+
emit "pow("
|
374
|
+
process(sexp[1])
|
375
|
+
emit ", "
|
376
|
+
process(sexp[3])
|
377
|
+
emit ")"
|
378
|
+
when :=~
|
379
|
+
emit "preg_match("
|
380
|
+
process(sexp[3])
|
381
|
+
emit ", "
|
382
|
+
process(sexp[1])
|
383
|
+
emit ")"
|
384
|
+
when :'!~'
|
385
|
+
emit "!preg_match("
|
386
|
+
process(sexp[3])
|
387
|
+
emit ", "
|
388
|
+
process(sexp[1])
|
389
|
+
emit ")"
|
390
|
+
else
|
391
|
+
raise NotImplementedError, sexp.inspect
|
392
|
+
end
|
42
393
|
when :var_ref
|
394
|
+
# probably need to remove this
|
43
395
|
if sexp[1][0] == :@kw
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
396
|
+
case sexp[1][1]
|
397
|
+
when 'false', 'true'
|
398
|
+
emit sexp[1][1].upcase
|
399
|
+
when 'nil'
|
400
|
+
emit 'NULL'
|
401
|
+
when '__FILE__', '__LINE__'
|
402
|
+
emit sexp[1][1]
|
403
|
+
else
|
404
|
+
raise NotImplementedError, sexp.inspect
|
405
|
+
end
|
406
|
+
elsif sexp[1][0] == :@ident
|
407
|
+
process sexp[1]
|
408
|
+
elsif sexp[1][0] == :@ivar
|
409
|
+
process sexp[1]
|
410
|
+
elsif sexp[1][0] == :@const
|
411
|
+
process sexp[1]
|
52
412
|
else
|
53
413
|
# later
|
54
|
-
raise NotImplementedError, sexp
|
414
|
+
raise NotImplementedError, sexp.inspect
|
55
415
|
end
|
56
416
|
else
|
57
417
|
raise NotImplementedError, sexp.inspect
|
data/lib/phaad/version.rb
CHANGED
data/lib/phaad.rb
CHANGED
data/phaad.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Utkarsh Kukreti"]
|
10
10
|
s.email = ["utkarshkukreti@gmail.com"]
|
11
|
-
s.homepage = ""
|
11
|
+
s.homepage = "https://github.com/utkarshkukreti/phaad/"
|
12
12
|
s.summary = %q{A beautiful way to write PHP}
|
13
13
|
s.description = %q{A beautiful way to write PHP}
|
14
14
|
|
@@ -19,5 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
+
s.add_dependency 'slop', '~>1.6.0'
|
23
|
+
s.add_dependency 'fssm', '~>0.2.7'
|
22
24
|
s.add_development_dependency 'rspec', '~>2.6.0'
|
23
25
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, 'array creation' do
|
4
|
+
context "linear arrays" do
|
5
|
+
it "should create blank array" do
|
6
|
+
compile("[]").should == "array();"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should create simple arrays" do
|
10
|
+
compile("[1, 'a', /b/, true]").should == 'array(1, "a", "/b/", TRUE);'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should create nested arrays" do
|
14
|
+
compile("[1, [1, [2, [3, [5, [8, 13]]]]]]").should ==
|
15
|
+
"array(1, array(1, array(2, array(3, array(5, array(8, 13))))));"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "associative arrays" do
|
20
|
+
it "should create blank array" do
|
21
|
+
compile("{}").should == "array();"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should create simple arrays" do
|
25
|
+
compile("{a => :b, 1 => 2, /foo/ => /bar/}").should ==
|
26
|
+
'array($a => "b", 1 => 2, "/foo/" => "/bar/");'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create nested arrays" do
|
30
|
+
compile("{1 => {2 => {3 => {4 => {5 => 6}}}}}").should ==
|
31
|
+
"array(1 => array(2 => array(3 => array(4 => array(5 => 6)))));"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should parse a mix of linear and associative arrays" do
|
36
|
+
compile("[{}, [], {foo => [1, 2, 3, {}]}]").should ==
|
37
|
+
"array(array(), array(), array($foo => array(1, 2, 3, array())));"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe Phaad::Generator, 'array access' do
|
42
|
+
context "linear arrays" do
|
43
|
+
it "should allow access" do
|
44
|
+
compile("a[0]") == "$a[0];"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "associative arrays" do
|
49
|
+
it "should allow access" do
|
50
|
+
compile("a['foo']") == '$a["foo"];'
|
51
|
+
compile("a[:foo]") == '$a["foo"];'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, 'assign' do
|
4
|
+
it "should assign simple variables" do
|
5
|
+
compile("a = 1").should == "$a = 1;"
|
6
|
+
compile('a = "foo"').should == '$a = "foo";'
|
7
|
+
compile("a = /foo/").should == '$a = "/foo/";'
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should assign array fields" do
|
11
|
+
compile("a[] = 1").should == "$a[] = 1;"
|
12
|
+
compile("a[0] = 1").should == "$a[0] = 1;"
|
13
|
+
compile("a['foo'] = 1").should == '$a["foo"] = 1;'
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, "binary" do
|
4
|
+
it "should parse +, -, *, /, %" do
|
5
|
+
compile("1 + 2").should == "1 + 2;"
|
6
|
+
compile("1 - 2").should == "1 - 2;"
|
7
|
+
compile("1 * 2").should == "1 * 2;"
|
8
|
+
compile("1 / 2").should == "1 / 2;"
|
9
|
+
compile("1 % 2").should == "1 % 2;"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should parse | & ^" do
|
13
|
+
compile("1 | 2").should == "1 | 2;"
|
14
|
+
compile("1 & 2").should == "1 & 2;"
|
15
|
+
compile("1 ^ 2").should == "1 ^ 2;"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse ** to pow" do
|
19
|
+
compile("1 ** 2").should == "pow(1, 2);"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should parse && ||" do
|
23
|
+
compile("true && false").should == "TRUE && FALSE;"
|
24
|
+
compile("true || false").should == "TRUE || FALSE;"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse 'and' and 'or'" do
|
28
|
+
compile("true and false").should == "TRUE && FALSE;"
|
29
|
+
compile("true or false").should == "TRUE || FALSE;"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should parse chain of binary statements" do
|
33
|
+
compile("1 + 2 - 3 + 4").should == "1 + 2 - 3 + 4;"
|
34
|
+
compile("1 + 2 ** 3 ** 4").should == "1 + pow(2, pow(3, 4));"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should parse == != > < >= <= ===" do
|
38
|
+
compile("1 == 2").should == "1 == 2;"
|
39
|
+
compile("1 != 2").should == "1 != 2;"
|
40
|
+
compile("1 > 2").should == "1 > 2;"
|
41
|
+
compile("1 < 2").should == "1 < 2;"
|
42
|
+
compile("1 >= 2").should == "1 >= 2;"
|
43
|
+
compile("1 <= 2").should == "1 <= 2;"
|
44
|
+
compile("1 === 2").should == "1 === 2;"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should parse =~ and !~ to preg_match statements" do
|
48
|
+
compile("a =~ b").should == "preg_match($b, $a);"
|
49
|
+
compile("a !~ b").should == "!preg_match($b, $a);"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should parse << as ." do
|
53
|
+
compile("'foo' << 'bar'").should == '"foo" . "bar";'
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, 'class' do
|
4
|
+
context 'define a class' do
|
5
|
+
it "should define a bare class" do
|
6
|
+
compile("class A; end").should == "class A {\n}"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should define a class which inherits" do
|
10
|
+
compile("class A < B; end").should == "class A extends B {\n}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'access object variables' do
|
15
|
+
it "should allow accessing a.b" do
|
16
|
+
compile("a.b").should == "$a->b;"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should allow accessing a.b.c.d.e" do
|
20
|
+
compile("a.b.c.d.e").should == "$a->b->c->d->e;"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "access object functions" do
|
25
|
+
it "should allow calling a.b()" do
|
26
|
+
compile("a.b()").should == "$a->b();"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should allow calling a.b c" do
|
30
|
+
compile("a.b c").should == "$a->b($c);"
|
31
|
+
compile("a.b(c)").should == "$a->b($c);"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow calling a.b c, d" do
|
35
|
+
compile("a.b c, d").should == "$a->b($c, $d);"
|
36
|
+
compile("a.b(c, d)").should == "$a->b($c, $d);"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "chained access" do
|
41
|
+
it "mix of chained variable and function calls" do
|
42
|
+
compile("a.b(c, d).e(f, g).h().i").should == "$a->b($c, $d)->e($f, $g)->h()->i;"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, 'constants' do
|
4
|
+
it "should allow referring to constants" do
|
5
|
+
compile("FOO").should == "FOO;"
|
6
|
+
end
|
7
|
+
|
8
|
+
# http://php.net/manual/en/language.constants.predefined.php
|
9
|
+
context "magic constants" do
|
10
|
+
it "should parse __LINE__" do
|
11
|
+
compile("__LINE__").should == "__LINE__;"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should parse __FILE__" do
|
15
|
+
compile("__FILE__").should == "__FILE__;"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse __DIR__" do
|
19
|
+
compile("__DIR__").should == "__DIR__;"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should parse __FUNCTION__" do
|
23
|
+
compile("__FUNCTION__").should == "__FUNCTION__;"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should parse __CLASS__" do
|
27
|
+
compile("__CLASS__").should == "__CLASS__;"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should parse __METHOD__" do
|
31
|
+
compile("__METHOD__").should == "__METHOD__;"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should parse __NAMESPACE__" do
|
35
|
+
compile("__NAMESPACE__").should == "__NAMESPACE__;"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, "for" do
|
4
|
+
context "over linear or associative arrays" do
|
5
|
+
it "should parse one variable for statements" do
|
6
|
+
compile("for a in b\nend").should == "foreach($b as $a) {\n}"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should parse two variable for statements" do
|
10
|
+
compile("for a, b in c\nend").should == "foreach($c as $a => $b) {\n}"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should parse the body" do
|
14
|
+
compile("for a, b in c\na\nb\nend").should == "foreach($c as $a => $b) {\n $a;\n $b;\n}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "over ranges" do
|
19
|
+
it "should loop over a simple range" do
|
20
|
+
compile("for a in 1..10\nend").should == "for($a = 1; $a <= 10; $a++) {\n}"
|
21
|
+
compile("for a in 1...10\nend").should == "for($a = 1; $a < 10; $a++) {\n}"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should loop over a dynamic range" do
|
25
|
+
compile("for a in 1..b\nend").should == "for($a = 1; $a <= $b; $a++) {\n}"
|
26
|
+
compile("for a in 1...b\nend").should == "for($a = 1; $a < $b; $a++) {\n}"
|
27
|
+
compile("for a in b..10\nend").should == "for($a = $b; $a <= 10; $a++) {\n}"
|
28
|
+
compile("for a in b...10\nend").should == "for($a = $b; $a < 10; $a++) {\n}"
|
29
|
+
compile("for a in b..c\nend").should == "for($a = $b; $a <= $c; $a++) {\n}"
|
30
|
+
compile("for a in b...c\nend").should == "for($a = $b; $a < $c; $a++) {\n}"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should parse the body" do
|
34
|
+
compile("for a in 1...10\na\nend").should == "for($a = 1; $a < 10; $a++) {\n $a;\n}"
|
35
|
+
compile("for a in b...c\na\nb\nc\nend").should ==
|
36
|
+
"for($a = $b; $a < $c; $a++) {\n $a;\n $b;\n $c;\n}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, 'call a function' do
|
4
|
+
it "should parse various function calls" do
|
5
|
+
compile("f()").should == "f();"
|
6
|
+
compile("f a").should == "f($a);"
|
7
|
+
compile("f(a)").should == "f($a);"
|
8
|
+
compile("f g a").should == "f(g($a));"
|
9
|
+
compile("f g(a)").should == "f(g($a));"
|
10
|
+
compile("a b c d, e, f()").should == "a(b(c($d, $e, f())));"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should not add brackets when calling global and echo" do
|
14
|
+
compile("echo a").should == "echo $a;"
|
15
|
+
compile("echo a, b").should == "echo $a, $b;"
|
16
|
+
compile("global a").should == "global $a;"
|
17
|
+
compile("global a, b").should == "global $a, $b;"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Phaad::Generator, 'define a function' do
|
22
|
+
it "should define a function without params" do
|
23
|
+
compile("def f\nend").should start_with("function f()")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should define a function with basic params" do
|
27
|
+
compile("def f a\nend").should start_with("function f($a)")
|
28
|
+
compile("def f(a)\nend").should start_with("function f($a)")
|
29
|
+
compile("def f a, b\nend").should start_with("function f($a, $b)")
|
30
|
+
compile("def f(a, b)\nend").should start_with("function f($a, $b)")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should define a function with params with default values" do
|
34
|
+
compile("def f a = 4\nend").should start_with("function f($a = 4)")
|
35
|
+
compile("def f a, b = 4\nend").should start_with("function f($a, $b = 4)")
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, "if" do
|
4
|
+
it "should parse if statements" do
|
5
|
+
compile("if a\nb\nend").should == "if($a) {\n $b;\n}"
|
6
|
+
compile("if a\nb\nc\nend").should == "if($a) {\n $b;\n $c;\n}"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should parse if else statements" do
|
10
|
+
compile("if a\nb\nelse\nc\nend").should == "if($a) {\n $b;\n} else {\n $c;\n}"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should parse if elsif statements" do
|
14
|
+
compile("if a\nb\nelsif c\nd\nend").should ==
|
15
|
+
"if($a) {\n $b;\n} elseif($c) {\n $d;\n}"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse if elsif else statements" do
|
19
|
+
compile("if a\nb\nelsif c\nd\nelse\n e\nend").should ==
|
20
|
+
"if($a) {\n $b;\n} elseif($c) {\n $d;\n} else {\n $e;\n}"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse if then end statements" do
|
24
|
+
compile("if a then b end").should == "if($a) {\n $b;\n}"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse if then else end statements" do
|
28
|
+
compile("if a then b else c end").should == "if($a) {\n $b;\n} else {\n $c;\n}"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should parse if then elsif else end statements" do
|
32
|
+
compile("if a then b elsif c then d else e end").should ==
|
33
|
+
"if($a) {\n $b;\n} elseif($c) {\n $d;\n} else {\n $e;\n}"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should parse one line if statements" do
|
37
|
+
compile("b if a").should == "if($a) {\n $b;\n}"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should parse unless statements" do
|
41
|
+
compile("unless a\nb\nend").should == "if(!($a)) {\n $b;\n}"
|
42
|
+
compile("unless a\nb\nc\nend").should == "if(!($a)) {\n $b;\n $c;\n}"
|
43
|
+
compile("unless a + b\nc\nend").should == "if(!($a + $b)) {\n $c;\n}"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should parse one line if statements" do
|
47
|
+
compile("b unless a").should == "if(!($a)) {\n $b;\n}"
|
48
|
+
end
|
49
|
+
end
|
@@ -2,36 +2,36 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Phaad::Generator, "Literals" do
|
4
4
|
it "should parse integers" do
|
5
|
-
compile("1").should == "1"
|
5
|
+
compile("1").should == "1;"
|
6
6
|
end
|
7
7
|
|
8
8
|
it "should parse floats" do
|
9
|
-
compile("1.0").should == "1.0"
|
9
|
+
compile("1.0").should == "1.0;"
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should parse strings" do
|
13
|
-
compile('"foo bar"').should == '"foo bar"'
|
14
|
-
compile("'foo bar'").should == '"foo bar"'
|
15
|
-
compile('"foo\nbar"').should == '"foo\nbar"'
|
13
|
+
compile('"foo bar"').should == '"foo bar";'
|
14
|
+
compile("'foo bar'").should == '"foo bar";'
|
15
|
+
compile('"foo\nbar"').should == '"foo\nbar";'
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should parse regexes" do
|
19
|
-
compile("/ab/").should == '"/ab/"'
|
20
|
-
compile("/ab/i").should == '"/ab/i"'
|
21
|
-
compile('/a\b/i').should == '"/a\\b/i"'
|
19
|
+
compile("/ab/").should == '"/ab/";'
|
20
|
+
compile("/ab/i").should == '"/ab/i";'
|
21
|
+
compile('/a\b/i').should == '"/a\\b/i";'
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should parse booleans" do
|
25
|
-
compile("true").should == "TRUE"
|
26
|
-
compile("false").should == "FALSE"
|
25
|
+
compile("true").should == "TRUE;"
|
26
|
+
compile("false").should == "FALSE;"
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should parse nil" do
|
30
|
-
compile("nil").should == "NULL"
|
30
|
+
compile("nil").should == "NULL;"
|
31
31
|
end
|
32
32
|
|
33
33
|
it "should parse symbols as strings" do
|
34
|
-
compile(":foo").should == '"foo"'
|
35
|
-
compile(':"foo"').should == '"foo"'
|
34
|
+
compile(":foo").should == '"foo";'
|
35
|
+
compile(':"foo"').should == '"foo";'
|
36
36
|
end
|
37
37
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
describe Phaad::Generator, 'massign' do
|
2
|
+
it "should multi-assign variables" do
|
3
|
+
compile("a, b = 1, 2").should == "$a = 1;\n$b = 2;"
|
4
|
+
compile('a, b = "foo", /foo/').should == "$a = \"foo\";\n$b = \"/foo/\";"
|
5
|
+
compile("a, b, c = 1, 2, 3").should == "$a = 1;\n$b = 2;\n$c = 3;"
|
6
|
+
compile("a, b, c, d = 1, 2, 3, 4").should == "$a = 1;\n$b = 2;\n$c = 3;\n$d = 4;"
|
7
|
+
compile("a, b, c, d, e, f, g, h, i, j = 1, 1, 2, 3, 5, 8, 13, 21, 34, 55").should ==
|
8
|
+
"$a = 1;\n$b = 1;\n$c = 2;\n$d = 3;\n$e = 5;\n$f = 8;\n$g = 13;\n$h = 21;\n" +
|
9
|
+
"$i = 34;\n$j = 55;"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, 'paren' do
|
4
|
+
it "should parse statements with parentheses" do
|
5
|
+
compile("(1)").should == "(1);"
|
6
|
+
compile("a + (b c)").should == "$a + (b($c));"
|
7
|
+
compile("a * (b + c * (d + e))").should == "$a * ($b + $c * ($d + $e));"
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, 'string' do
|
4
|
+
it "should parse empty strings" do
|
5
|
+
compile("''").should == '"";'
|
6
|
+
compile('""').should == '"";'
|
7
|
+
end
|
8
|
+
context "escaping" do
|
9
|
+
it "should parse double quotes" do
|
10
|
+
compile(%q{'"'}).should == %q{"\"";}
|
11
|
+
compile(%q{'\"'}).should == %q{"\\\"";}
|
12
|
+
compile(%q{'\\"'}).should == %q{"\\\"";}
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Ripper parses single quotes the same as double quotes. There's no way to
|
17
|
+
# know if a single quote was used or a double quote was.
|
18
|
+
# it "should respect escape sequences in single and double quotes" do
|
19
|
+
# compile(%q{"\n"}).should == %q{"\\n";}
|
20
|
+
# compile(%q{'\n'}).should == %q{"\\\\n";}
|
21
|
+
# end
|
22
|
+
end
|
23
|
+
context "string interpolation" do
|
24
|
+
it "should parse simple interpolation" do
|
25
|
+
compile('"a #{b}"').should == '"a " . $b;'
|
26
|
+
compile('"a #{b c}"').should == '"a " . b($c);'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should parse complex interpolation" do
|
30
|
+
compile('"a #{b} #{foo("bar", :baz)} "').should ==
|
31
|
+
'"a " . $b . " " . foo("bar", "baz") . " ";'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should handle empty \#{} properly" do
|
35
|
+
compile('"a #{b} #{} "').should == '"a " . $b . " " . " ";'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
describe Phaad::Generator, 'Unary' do
|
2
|
+
it "should parse +" do
|
3
|
+
compile("+a").should == "+$a;"
|
4
|
+
end
|
5
|
+
it "should parse -" do
|
6
|
+
compile("-a").should == "-$a;"
|
7
|
+
end
|
8
|
+
it "should parse ~" do
|
9
|
+
compile("~a").should == "~$a;"
|
10
|
+
end
|
11
|
+
it "should parse !" do
|
12
|
+
compile("!a").should == "!$a;"
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, "while" do
|
4
|
+
it "should parse while statements" do
|
5
|
+
compile("while a\nb\nend").should == "while($a) {\n $b;\n}"
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should parse one line while statements" do
|
9
|
+
compile("b while a").should == "while($a) {\n $b;\n}"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should parse until statements" do
|
13
|
+
compile("until a\nb\nend").should == "while(!($a)) {\n $b;\n}"
|
14
|
+
compile("until a + b\nc\nend").should == "while(!($a + $b)) {\n $c;\n}"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should parse one line until statements" do
|
18
|
+
compile("b until a").should == "while(!($a)) {\n $b;\n}"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Phaad::Generator, "Whitespace" do
|
4
|
+
it "should correctly parse this huge program" do
|
5
|
+
input = <<EOT
|
6
|
+
def complex_hello_world(name = "Foo Bar", greeting = "Howdy")
|
7
|
+
print_greeting greeting
|
8
|
+
print_name name
|
9
|
+
echo "Howdy is cooler!" if greeting != "Howdy"
|
10
|
+
echo "Impossible" unless 1 == 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def print_name(name)
|
14
|
+
if name == "Foo Bar"
|
15
|
+
i = 0
|
16
|
+
while i < 10
|
17
|
+
echo "Your name is not 'Foo Bar'"
|
18
|
+
i = i + 1
|
19
|
+
end
|
20
|
+
elsif name == "1337"
|
21
|
+
echo "l33t" while true
|
22
|
+
else
|
23
|
+
echo name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def print_greeting(greeting)
|
28
|
+
if greeting == "Howdy"
|
29
|
+
complex_hello_world "Foo Bar", "Bug"
|
30
|
+
echo greeting until true
|
31
|
+
else
|
32
|
+
echo greeting
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
complex_hello_world "Utkarsh"
|
37
|
+
EOT
|
38
|
+
|
39
|
+
expected_output = <<EOT
|
40
|
+
function complex_hello_world($name = "Foo Bar", $greeting = "Howdy") {
|
41
|
+
print_greeting($greeting);
|
42
|
+
print_name($name);
|
43
|
+
if($greeting != "Howdy") {
|
44
|
+
echo "Howdy is cooler!";
|
45
|
+
}
|
46
|
+
if(!(1 == 1)) {
|
47
|
+
echo "Impossible";
|
48
|
+
}
|
49
|
+
}
|
50
|
+
function print_name($name) {
|
51
|
+
if($name == "Foo Bar") {
|
52
|
+
$i = 0;
|
53
|
+
while($i < 10) {
|
54
|
+
echo "Your name is not 'Foo Bar'";
|
55
|
+
$i = $i + 1;
|
56
|
+
}
|
57
|
+
} elseif($name == "1337") {
|
58
|
+
while(TRUE) {
|
59
|
+
echo "l33t";
|
60
|
+
}
|
61
|
+
} else {
|
62
|
+
echo $name;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
function print_greeting($greeting) {
|
66
|
+
if($greeting == "Howdy") {
|
67
|
+
complex_hello_world("Foo Bar", "Bug");
|
68
|
+
while(!(TRUE)) {
|
69
|
+
echo $greeting;
|
70
|
+
}
|
71
|
+
} else {
|
72
|
+
echo $greeting;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
complex_hello_world("Utkarsh");
|
76
|
+
EOT
|
77
|
+
|
78
|
+
compile(input).should == expected_output.chomp
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should parse this class program" do
|
82
|
+
input = <<EOT
|
83
|
+
class Foo
|
84
|
+
def bar
|
85
|
+
@came = 1
|
86
|
+
return true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
EOT
|
90
|
+
|
91
|
+
expected_output = <<EOT
|
92
|
+
class Foo {
|
93
|
+
function bar() {
|
94
|
+
$this->came = 1;
|
95
|
+
return TRUE;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
EOT
|
99
|
+
compile(input).should == expected_output.chomp
|
100
|
+
end
|
101
|
+
end
|
data/spec/phaad_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phaad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-06-01 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: slop
|
16
|
+
requirement: &75976660 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *75976660
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: fssm
|
27
|
+
requirement: &76004900 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.2.7
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *76004900
|
14
36
|
- !ruby/object:Gem::Dependency
|
15
37
|
name: rspec
|
16
|
-
requirement: &
|
38
|
+
requirement: &76018460 !ruby/object:Gem::Requirement
|
17
39
|
none: false
|
18
40
|
requirements:
|
19
41
|
- - ~>
|
@@ -21,7 +43,7 @@ dependencies:
|
|
21
43
|
version: 2.6.0
|
22
44
|
type: :development
|
23
45
|
prerelease: false
|
24
|
-
version_requirements: *
|
46
|
+
version_requirements: *76018460
|
25
47
|
description: A beautiful way to write PHP
|
26
48
|
email:
|
27
49
|
- utkarshkukreti@gmail.com
|
@@ -33,6 +55,7 @@ files:
|
|
33
55
|
- .gitignore
|
34
56
|
- .rspec
|
35
57
|
- Gemfile
|
58
|
+
- README.md
|
36
59
|
- Rakefile
|
37
60
|
- bin/phaad
|
38
61
|
- lib/phaad.rb
|
@@ -40,10 +63,27 @@ files:
|
|
40
63
|
- lib/phaad/generator.rb
|
41
64
|
- lib/phaad/version.rb
|
42
65
|
- phaad.gemspec
|
66
|
+
- spec/generator/array_spec.rb
|
67
|
+
- spec/generator/assign_spec.rb
|
68
|
+
- spec/generator/binary_spec.rb
|
69
|
+
- spec/generator/class_spec.rb
|
70
|
+
- spec/generator/constants_spec.rb
|
71
|
+
- spec/generator/for_spec.rb
|
72
|
+
- spec/generator/function_spec.rb
|
73
|
+
- spec/generator/if_spec.rb
|
74
|
+
- spec/generator/ivar_spec.rb
|
43
75
|
- spec/generator/literal_spec.rb
|
76
|
+
- spec/generator/massign_spec.rb
|
77
|
+
- spec/generator/paren_spec.rb
|
78
|
+
- spec/generator/return_spec.rb
|
79
|
+
- spec/generator/string_spec.rb
|
80
|
+
- spec/generator/ternary_spec.rb
|
81
|
+
- spec/generator/unary_spec.rb
|
82
|
+
- spec/generator/while_spec.rb
|
83
|
+
- spec/generator/whitespace_spec.rb
|
44
84
|
- spec/phaad_spec.rb
|
45
85
|
- spec/spec_helper.rb
|
46
|
-
homepage:
|
86
|
+
homepage: https://github.com/utkarshkukreti/phaad/
|
47
87
|
licenses: []
|
48
88
|
post_install_message:
|
49
89
|
rdoc_options: []
|