Permalink
Browse files

Adopted Ruby's global variables (e.g. `$foo`) for generating PHP loca…

…l variables.

This was necessary since references to local variables (e.g. `foo`) can't be
reliably distinguished from implicit-self method calls (so-called vcalls,
where `foo` could in fact potentially be the equivalent of `foo()`) in the
parse tree generated from Ruby code.
  • Loading branch information...
1 parent 7656190 commit 50bda4469d5e2391292f3865b1928db8327155ef Arto Bendiken committed Jan 20, 2010
Showing with 127 additions and 129 deletions.
  1. +43 −33 README.md
  2. +2 −2 doc/examples/foreach1.rb
  3. +2 −2 doc/examples/foreach2.rb
  4. +9 −21 lib/php/generator.rb
  5. +71 −71 spec/php_generator_spec.rb
View
@@ -38,10 +38,21 @@ The following snippets demonstrate the PHP output generated by `PHP.rb`
for the given Ruby code. Look in the `doc/examples/` directory for runnable
Ruby scripts containing these examples.
+### Function definitions
+
+ def unid
+ return md5(uniqid(mt_rand, true))
+ end
+
+ <?php
+ function unid() {
+ return md5(uniqid(mt_rand(), TRUE));
+ }
+
### `foreach` loops (1)
- for fruit in ['apple', 'banana', 'cranberry']
- echo "#{fruit}\n"
+ for $fruit in ['apple', 'banana', 'cranberry']
+ echo "#{$fruit}\n"
end
<?php
@@ -51,8 +62,8 @@ Ruby scripts containing these examples.
### `foreach` loops (2)
- for key, value in {'a' => 1, 'b' => 2, 'c' => 3}
- echo "#{key} => #{value}\n"
+ for $key, $value in {'a' => 1, 'b' => 2, 'c' => 3}
+ echo "#{$key} => #{$value}\n"
end
<?php
@@ -62,9 +73,9 @@ Ruby scripts containing these examples.
### `while` loops
- result = mysql_query("SELECT name FROM user")
- while row = mysql_fetch_assoc(result)
- echo "User.name = #{row['name']}\n"
+ $result = mysql_query("SELECT name FROM user")
+ while $row = mysql_fetch_assoc($result)
+ echo "User.name = #{$row['name']}\n"
end
<?php
@@ -88,47 +99,45 @@ special semantics that need to be taken into account.
42 | 42
3.1415 | 3.1415
"Hello, world!" | "Hello, world!"
- "<#{url}>" | "<" . $url . ">"
+ "<#{$url}>" | "<" . $url . ">"
/a-z/ | '/a-z/'
[] | array()
[1, 2, 3] | array(1, 2, 3)
{} | array()
{"a" => 1, "b" => 2, "c" => 3} | array("a" => 1, "b" => 2, "c" => 3)
- $foo | $GLOBALS['foo']
- $foo = 123 | $GLOBALS['foo'] = 123
- foo | $foo
- foo = 123 | $foo = 123
- lambda { |x, y| } | function($x, $y) {}
+ $foo | $foo
+ $foo = 123 | $foo = 123
+ lambda { |$x, $y| } | function($x, $y) {}
def foo(x, y); end | function foo($x, $y) {}
- a << b | $a . $b (*)
- a + b | $a + $b
- a - b | $a - $b
- a * b | $a * $b
- a / b | $a / $b
- a % b | $a % $b
- a = b | $a = $b
- a == b | $a == $b
- a === b | $a === $b (*)
- a != b | $a != $b
- a < b | $a < $b
- a > b | $a > $b
- a <= b | $a <= $b
- a >= b | $a >= $b
- array[index] | $array[$index]
- object[:property] | $object->property (*)
- object.method | $object->method()
+ $a << $b | $a . $b (*)
+ $a + $b | $a + $b
+ $a - $b | $a - $b
+ $a * $b | $a * $b
+ $a / $b | $a / $b
+ $a % $b | $a % $b
+ $a = $b | $a = $b
+ $a == $b | $a == $b
+ $a === $b | $a === $b (*)
+ $a != $b | $a != $b
+ $a < $b | $a < $b
+ $a > $b | $a > $b
+ $a <= $b | $a <= $b
+ $a >= $b | $a >= $b
+ $array[$index] | $array[$index]
+ $object[:property] | $object->property (*)
+ $object.method | $object->method()
Limitations
-----------
### Method calls vs property access
-Ruby method calls, e.g. `user.name`, are in principle ambiguous when
+Ruby method calls, e.g. `$user.name`, are in principle ambiguous when
translated into PHP, because they could resolve into either a property
access as in `$user->name` or a method call as in `$user->name()`.
-Therefore `PHP.rb` defines `user.name` to be equivalent to the latter (the
-method call), and defines the syntax `user[:name]` to be equivalent to the
+Therefore `PHP.rb` defines `$user.name` to be equivalent to the latter (the
+method call), and defines the syntax `$user[:name]` to be equivalent to the
former (the property access).
Note that this does not conflict with array subscript access since Ruby
@@ -144,6 +153,7 @@ Methods
* {PHP.eval}
* {PHP.exec}
+* {PHP.dump}
* {PHP.generate}
* {PHP.version}
@@ -2,7 +2,7 @@
require 'php'
PHP.eval do
- for fruit in ['apple', 'banana', 'cranberry']
- echo "#{fruit}\n"
+ for $fruit in ['apple', 'banana', 'cranberry']
+ echo "#{$fruit}\n"
end
end
@@ -2,7 +2,7 @@
require 'php'
PHP.eval do
- for key, value in {'a' => 1, 'b' => 2, 'c' => 3}
- echo "#{key} => #{value}\n"
+ for $key, $value in {'a' => 1, 'b' => 2, 'c' => 3}
+ echo "#{$key} => #{$value}\n"
end
end
View
@@ -144,7 +144,7 @@ def process_hash(exp)
# @param [Array(Symbol)] exp
# @return [Variable]
def process_gvar(exp)
- Variable.new(exp.shift.to_s[1..-1], :global => true) # NOTE: removes the leading '$' character
+ Variable.new(exp.shift.to_s[1..-1]) # NOTE: removes the leading '$' character
end
##
@@ -156,9 +156,9 @@ def process_gvar(exp)
# @param [Array(Symbol, Array)] exp
# @return [Operator::Assignment]
def process_gasgn(exp)
- var = Variable.new(exp.shift.to_s[1..-1], :global => true) # NOTE: removes the leading '$' character
+ var = Variable.new(exp.shift.to_s[1..-1]) # NOTE: removes the leading '$' character
val = process(exp.shift)
- Operator::Assignment.new(var, val)
+ val ? Operator::Assignment.new(var, val) : var
end
##
@@ -182,12 +182,7 @@ def process_lvar(exp)
# @param [Array(Symbol)] exp
# @return [Variable]
def process_vcall(exp) # FIXME
- if exp.size == 1
- # FIXME: for now, we're assuming this is a reference to a local variable:
- Variable.new(exp.shift)
- else
- raise NotImplementedError.new(exp.inspect) # TODO
- end
+ raise NotImplementedError.new(exp.inspect) # TODO
end
##
@@ -199,22 +194,15 @@ def process_vcall(exp) # FIXME
#
# @param [Array] exp
# @return [Node]
- def process_call(exp) # FIXME
+ def process_call(exp)
receiver, method, arglist = exp
- if receiver.nil?
- arglist = process(arglist)
- if arglist.to_a.empty?
- # FIXME: for now, we're assuming this is a reference to a local variable:
- Variable.new(method)
- else
- Function::Call.new(method, *arglist)
- end
- else
- if op = Operator.for(method)
+ case
+ when receiver.nil?
+ Function::Call.new(method, *process(arglist))
+ when op = Operator.for(method)
op.new(process(receiver), *process(arglist))
else
Method::Call.new(process(receiver), method, *process(arglist))
- end
end
end
Oops, something went wrong.

0 comments on commit 50bda44

Please sign in to comment.