phaad 0.0.1 → 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.
- 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: []
|