farleyknight-ionize 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/README.rdoc +59 -0
  2. data/Rakefile +5 -0
  3. data/bin/ionize +47 -0
  4. data/lib/ionize.rb +75 -0
  5. data/lib/ionize/environment.rb +56 -0
  6. data/lib/ionize/environment/application.rb +58 -0
  7. data/lib/ionize/environment/php_array.rb +95 -0
  8. data/lib/ionize/parser.rb +272 -0
  9. data/lib/ionize/tokenizer.rb +544 -0
  10. data/lib/ionize/translate.rb +34 -0
  11. data/lib/ionize/translate/composite_string_statements.rb +79 -0
  12. data/lib/ionize/translate/debug.rb +16 -0
  13. data/lib/ionize/translate/ext.rb +47 -0
  14. data/lib/ionize/translate/function_args.rb +132 -0
  15. data/lib/ionize/translate/if_statements.rb +42 -0
  16. data/lib/ionize/translate/multiple_statements.rb +22 -0
  17. data/lib/ionize/translate/php_to_ruby.rb +40 -0
  18. data/lib/ionize/translate/rails_for_php.rb +191 -0
  19. data/lib/ionize/translate/rewritable.rb +133 -0
  20. data/lib/ionize/translate/rewrites.rb +51 -0
  21. data/lib/ionize/translate/statements.rb +622 -0
  22. data/lib/ionize/translate/switch_case_statements.rb +52 -0
  23. data/lib/ionize/translate/term_statements.rb +76 -0
  24. data/lib/ionize/translate/translator.rb +52 -0
  25. data/lib/ionize/version.rb +9 -0
  26. data/spec/fixtures/array_lookup.php +10 -0
  27. data/spec/fixtures/boolean_operators.php +5 -0
  28. data/spec/fixtures/boolean_operators.rb +6 -0
  29. data/spec/fixtures/class_def.php +34 -0
  30. data/spec/fixtures/class_def.rb +34 -0
  31. data/spec/fixtures/dangling_else.php +8 -0
  32. data/spec/fixtures/dangling_else.rb +12 -0
  33. data/spec/fixtures/drupal_1.php +663 -0
  34. data/spec/fixtures/drupal_2.php +1152 -0
  35. data/spec/fixtures/empty_string.php +12 -0
  36. data/spec/fixtures/for_loop.php +17 -0
  37. data/spec/fixtures/for_loop2.php +13 -0
  38. data/spec/fixtures/for_loop3.php +16 -0
  39. data/spec/fixtures/for_loop3.rb +17 -0
  40. data/spec/fixtures/for_loop4.php +5 -0
  41. data/spec/fixtures/for_loop4.rb +6 -0
  42. data/spec/fixtures/foreach.php +9 -0
  43. data/spec/fixtures/foreach2.php +8 -0
  44. data/spec/fixtures/foreach3.php +7 -0
  45. data/spec/fixtures/foreach3.rb +7 -0
  46. data/spec/fixtures/fun_def.php +9 -0
  47. data/spec/fixtures/fun_def2.php +30 -0
  48. data/spec/fixtures/fun_def2.rb +30 -0
  49. data/spec/fixtures/fun_def3.php +33 -0
  50. data/spec/fixtures/fun_def4.php +43 -0
  51. data/spec/fixtures/fun_def4.rb +37 -0
  52. data/spec/fixtures/fun_def5.php +36 -0
  53. data/spec/fixtures/fun_with_if.php +6 -0
  54. data/spec/fixtures/fun_with_if.rb +6 -0
  55. data/spec/fixtures/fun_with_ifs.php +12 -0
  56. data/spec/fixtures/fun_with_ifs.rb +14 -0
  57. data/spec/fixtures/hello_world.php +6 -0
  58. data/spec/fixtures/heredoc.php +6 -0
  59. data/spec/fixtures/heredoc.rb +5 -0
  60. data/spec/fixtures/if.php +6 -0
  61. data/spec/fixtures/if.rb +7 -0
  62. data/spec/fixtures/if_boolean.php +5 -0
  63. data/spec/fixtures/if_boolean.rb +5 -0
  64. data/spec/fixtures/if_else.php +11 -0
  65. data/spec/fixtures/if_else1.php +17 -0
  66. data/spec/fixtures/if_else2.php +8 -0
  67. data/spec/fixtures/if_else3.php +15 -0
  68. data/spec/fixtures/if_else_nested.php +14 -0
  69. data/spec/fixtures/if_else_nested.rb +15 -0
  70. data/spec/fixtures/if_else_series.php +12 -0
  71. data/spec/fixtures/if_else_series.rb +12 -0
  72. data/spec/fixtures/if_not.php +5 -0
  73. data/spec/fixtures/if_not.rb +5 -0
  74. data/spec/fixtures/if_with_brackets.php +7 -0
  75. data/spec/fixtures/if_with_brackets.rb +7 -0
  76. data/spec/fixtures/long_if_else.php +10 -0
  77. data/spec/fixtures/long_if_else.rb +9 -0
  78. data/spec/fixtures/oo.php +16 -0
  79. data/spec/fixtures/php_nuke/sql_layer.php +527 -0
  80. data/spec/fixtures/postop.php +3 -0
  81. data/spec/fixtures/preop.php +7 -0
  82. data/spec/fixtures/simple_fun_def.php +4 -0
  83. data/spec/fixtures/switch_case.php +13 -0
  84. data/spec/fixtures/switch_case.rb +14 -0
  85. data/spec/fixtures/switch_case2.php +25 -0
  86. data/spec/fixtures/switch_case3.php +40 -0
  87. data/spec/fixtures/switch_case3.rb +42 -0
  88. data/spec/fixtures/switch_case4.php +56 -0
  89. data/spec/fixtures/switch_case5.php +71 -0
  90. data/spec/fixtures/switch_case_with_rescue_nil.php +43 -0
  91. data/spec/fixtures/switch_case_with_rescue_nil.rb +35 -0
  92. data/spec/fixtures/tertiary.php +3 -0
  93. data/spec/helper.rb +17 -0
  94. data/spec/php_environment_spec.rb +83 -0
  95. data/spec/php_parser_spec.rb +121 -0
  96. data/spec/php_translator_spec.rb +358 -0
  97. data/spec/rails_for_php_spec.rb +303 -0
  98. metadata +191 -0
@@ -0,0 +1,59 @@
1
+ = Ionize
2
+
3
+ == DESCRIPTION:
4
+
5
+ Tranforms Php to Ruby.
6
+
7
+ Ionize parses Php, turns the parse result into an s-expression, then translates
8
+ the s-expression into one that can be consumed by Ruby2Ruby. When everything is
9
+ said and done, it will be able to translate an entire Php installation into Ruby.
10
+
11
+ == FEATURES/PROBLEMS:
12
+
13
+ Check out http://ionize.farleyknight.com for some examples of what
14
+ works and what doesn't.
15
+
16
+ == SYNOPSIS:
17
+
18
+ TODO: Add an example of using a command line tool to convert
19
+ an existing Php installation into a Ruby one
20
+
21
+ == REQUIREMENTS:
22
+
23
+ Dhaka, ParseTree, Ruby2Ruby
24
+
25
+ The Rspec gem is required to run the specs..
26
+
27
+ , .. anything else?
28
+
29
+ == INSTALL:
30
+
31
+ When I register this project with Rubygems, the command will be:
32
+ sudo gem install ionize
33
+
34
+ But, at the moment, we're still in development..
35
+
36
+ == LICENSE:
37
+
38
+ (The MIT License)
39
+
40
+ Copyright (c) 2008 Farley Knight
41
+
42
+ Permission is hereby granted, free of charge, to any person obtaining
43
+ a copy of this software and associated documentation files (the
44
+ 'Software'), to deal in the Software without restriction, including
45
+ without limitation the rights to use, copy, modify, merge, publish,
46
+ distribute, sublicense, and/or sell copies of the Software, and to
47
+ permit persons to whom the Software is furnished to do so, subject to
48
+ the following conditions:
49
+
50
+ The above copyright notice and this permission notice shall be
51
+ included in all copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
54
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
56
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
57
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
58
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
59
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,5 @@
1
+ # require 'config/requirements'
2
+ # require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
5
+
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This is stupid..
4
+ require '/home/robinhoode/dev/ruby/ionize/lib/ionize'
5
+
6
+ module Ionize
7
+ module Php
8
+ class Convert
9
+ def run
10
+ if ARGV.first =~ /\.php$/
11
+ # convert_file(ARGV.first)
12
+ elsif File.stat(ARGV.first).directory?
13
+ puts "#{ARGV.first} was a directory. Converting.."
14
+ convert_directory(ARGV.first)
15
+ else
16
+ # Should actually print the usage here..
17
+ raise "First argument was neither php file nor directory: #{ARGV.first.inspect}"
18
+ end
19
+ end
20
+
21
+ def convert_file(php_file, ruby_file = nil)
22
+ ruby_file ||= php_file.gsub(".php", ".rb")
23
+
24
+ ruby_dir = File.dirname(ruby_file)
25
+ FileUtils.mkdir_p(ruby_dir) unless File.exists?(ruby_dir)
26
+
27
+ File.open(ruby_file, "w+") do |f|
28
+ f.write(Ionize::Php.to_ruby(File.read(php_file)))
29
+ end
30
+ puts "Converted file #{php_file} and stored it as #{ruby_file}"
31
+ end
32
+
33
+ def convert_directory(php_directory, ruby_directory = nil)
34
+ ruby_directory ||= "#{php_directory}-ruby"
35
+ FileUtils.mkdir ruby_directory unless File.exists?(ruby_directory) and File.stat(ruby_directory).directory?
36
+ Dir["#{php_directory}/**/*"].select {|f| f =~ /\.php$/ }.each do |php_file|
37
+ ruby_file = php_file.gsub(php_directory, ruby_directory).gsub(".php", ".rb")
38
+ puts "Found file #{php_file}"
39
+ convert_file(php_file, ruby_file)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+
47
+ Ionize::Php::Convert.new.run
@@ -0,0 +1,75 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'dhaka'
6
+ require 'parse_tree'
7
+ require 'ruby2ruby'
8
+
9
+ require 'ionize/translate'
10
+ require 'ionize/environment'
11
+
12
+ require 'ionize/parser'
13
+ require 'ionize/compiled_parser'
14
+
15
+ module Ionize
16
+ module Php
17
+ CharacterLimit = 50000
18
+
19
+ # Returns a Dhaka AST of a string
20
+ def self.to_ast(string)
21
+ # TODO: Error handling could be better..
22
+ # Maybe another time
23
+
24
+ if string.length > CharacterLimit
25
+ raise "Your input is #{string.length}. Ionize::Php::Parser currently cannot handle inputs larger than #{CharacterLimit}, due to Dhaka's memory usage"
26
+ end
27
+
28
+ tokens = Php.to_tokens(string)
29
+ result = Php::CompiledParser.parse(tokens)
30
+
31
+ if result.is_a? Dhaka::ParseErrorResult
32
+ error = %Q{
33
+ Could not parse token.
34
+ Token => #{result.unexpected_token.inspect}
35
+
36
+ }
37
+ error << string.slice(result.unexpected_token.input_position, 40) rescue nil
38
+ raise error
39
+ elsif result.is_a? Dhaka::TokenizerErrorResult
40
+ raise result
41
+ end
42
+
43
+ result
44
+ end
45
+
46
+ # Tokens from Dhaka's tokenizer
47
+ def self.to_tokens(string)
48
+ require 'ionize/tokenizer'
49
+ tokenizer = Php::Tokenizer.new(string)
50
+ tokenizer.switch_to :php unless string =~ /<\?php/i
51
+ tokens = tokenizer.run
52
+
53
+ if tokens.is_a? Dhaka::TokenizerErrorResult
54
+ raise "Could not tokenize at index #{tokens.unexpected_char_index}\n" + string.slice(tokens.unexpected_char_index, 40).inspect
55
+ end
56
+
57
+ tokens
58
+ end
59
+
60
+ # An S-expression of the string
61
+ def self.to_sexp(string)
62
+ Php::Translate.translate(Php.to_ast(string))
63
+ end
64
+
65
+ # A stripped down version of what Dhaka hands us
66
+ def self.to_raw_sexp(string)
67
+ Php::Translate.flatten(Php.to_ast(string))
68
+ end
69
+
70
+ # Abracadbra!
71
+ def self.to_ruby(string)
72
+ Php::Translate::Php2Ruby.new.process(Php.to_sexp(string))
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,56 @@
1
+
2
+ load File.dirname(__FILE__) + '/environment/php_array.rb'
3
+ load File.dirname(__FILE__) + '/environment/application.rb'
4
+
5
+ module Ionize
6
+ module Php
7
+ Config = {
8
+ "magic_quotes_gpc" => true,
9
+ "magic_quotes_runtime" => true
10
+ }
11
+ module Environment
12
+ def self.included(target)
13
+ Kernel.module_eval do
14
+ def array(*args)
15
+ PhpArray.from_mixed(*args)
16
+ end
17
+
18
+ def get_magic_quotes_gpc
19
+ Php::Config["magic_quotes_gpc"] ? 1 : 0
20
+ end
21
+
22
+ def get_magic_quotes_runtime
23
+ Php::Config["magic_quotes_runtime"] ? 1 : 0
24
+ end
25
+
26
+ def gethostbyaddr(string)
27
+ address = string.split(".").map {|n| n.to_i }.pack("CCCC")
28
+ Socket.gethostbyaddr(address).first
29
+ end
30
+ end
31
+
32
+ String.class_eval do
33
+ def preg_match(regex)
34
+ matches = match(regex)
35
+ return [!matches.nil?, matches.to_a]
36
+ end
37
+
38
+ def preg_match_all(regex)
39
+ copy = self.dup
40
+ results = []
41
+
42
+ match = copy.match(regex)
43
+ while match
44
+ results << match.to_a
45
+ copy.gsub!(match.to_a.first, "")
46
+ match = copy.match(regex)
47
+ end
48
+
49
+ [results.length - 1, results.transpose]
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,58 @@
1
+
2
+ require 'rack'
3
+
4
+ module Ionize
5
+ module Php
6
+ module Environment
7
+ class ScriptExit < Exception; end
8
+
9
+ class Application
10
+ def self.run(code)
11
+ Rack::Handler::Mongrel.run(Application.new(code), :Port => 3000)
12
+ end
13
+
14
+ def initialize(code)
15
+ @output, @header, @code = "", {}, 200
16
+ @php_script = Php.to_ruby(code)
17
+ end
18
+
19
+ def GET
20
+ @get ||= @request.GET
21
+ end
22
+
23
+ def POST
24
+ @post ||= @request.POST
25
+ end
26
+
27
+ def SERVER
28
+ @server ||= @requeset.SERVER
29
+ end
30
+
31
+ def exit
32
+ raise ScriptExit
33
+ end
34
+
35
+ def print(text)
36
+ @output << text
37
+ end
38
+
39
+ def header(string)
40
+ if m = string.match(/Location: (.*)/i)
41
+ @header["Location"] = m[1]
42
+ @code = 302
43
+ end
44
+ end
45
+
46
+ def call(env)
47
+ @request = Rack::Request.new(env)
48
+ begin
49
+ instance_eval(@php_script)
50
+ rescue ScriptExit
51
+ # Catch an exit() or die() and show that to the user
52
+ end
53
+ [@code, @header, @output]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,95 @@
1
+
2
+ module Ionize
3
+ module Php
4
+ module Environment
5
+ class PhpArray < Hash
6
+ def initialize(*args, &block)
7
+ @index = 0
8
+ super(*args, &block)
9
+ end
10
+
11
+ def join(*args)
12
+ values.join(*args)
13
+ end
14
+
15
+ def hash?
16
+ keys.any? {|k| k.class != Fixnum }
17
+ end
18
+
19
+ def array?
20
+ keys.all? {|k| k.class == Fixnum }
21
+ end
22
+
23
+ def combine(second)
24
+ array = self.class.new
25
+ second.values.each_with_index do |val, key|
26
+ array.put(self[key], val)
27
+ end
28
+ array
29
+ end
30
+
31
+ def intersect(second)
32
+ array = self.class.new
33
+ second.values.each do |value|
34
+ if self.values.include? value
35
+ key = self.to_a.select {|k,v| v == value }.first.first
36
+ array.put(key, value)
37
+ end
38
+ end
39
+ array
40
+ end
41
+
42
+ def add(value)
43
+ put(@index, value)
44
+ end
45
+
46
+ def put(key, value)
47
+ if key.is_a? Fixnum and key >= @index
48
+ @index = key+1
49
+ end
50
+ self[key] = value
51
+ end
52
+
53
+ def to_hash
54
+ Hash[*(self.to_a).flatten]
55
+ end
56
+
57
+ def merge(other)
58
+ if self.array? and other.array?
59
+ self.class.from_array(*(self.values + other.values))
60
+ else
61
+ self.class.from_hash(super(other))
62
+ end
63
+ end
64
+
65
+ def self.from_mixed(*args)
66
+ array = self.new
67
+ args.each do |arg|
68
+ if arg.is_a? Hash
69
+ arg.each {|key, value| array.put(key, value)}
70
+ else
71
+ array.add(arg)
72
+ end
73
+ end
74
+ array
75
+ end
76
+
77
+ def self.from_hash(hash)
78
+ array = self.new
79
+ hash.each {|key, value| array.put(key, value)}
80
+ array
81
+ end
82
+
83
+ def self.from_array(*args)
84
+ array = self.new
85
+ args.each {|arg| array.add(arg)}
86
+ array
87
+ end
88
+
89
+ def inspect
90
+ "array(" + super.gsub("{", "").gsub("}", "") + ")"
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,272 @@
1
+
2
+ require 'rubygems'
3
+ require 'dhaka'
4
+
5
+ class Dhaka::Grammar
6
+ def for_rule(hash)
7
+ i = 0
8
+ name = hash.keys.first
9
+ for_symbol(name) do
10
+ hash.values.first.split("|").each do |s|
11
+ send "#{name}_#{i += 1}", *(s.split)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ module Ionize
18
+ module Php
19
+ class Grammar < Dhaka::Grammar
20
+ precedences do
21
+ left %w{ expr }
22
+ left %w{ tertiary }
23
+ left %w{ + - }
24
+ left %w{ term_plus_expr term_minus_expr }
25
+ left %w{ preop op }
26
+ left %w{ fun_call fun_call_wo_parens }
27
+ end
28
+
29
+ for_symbol(Dhaka::START_SYMBOL_NAME) do
30
+ html_file_with_php_with_end_and_html_string %w{ html_string php_start statements php_end html_string }
31
+ html_file_with_php_with_end %w{ html_string php_start statements php_end }
32
+ html_file_with_php_without_end %w{ html_string php_start statements }
33
+ php_file %w{ statements }
34
+ end
35
+
36
+ for_symbol 'statements' do
37
+ multiple_statements %w{ statement statements }
38
+ single_statement %w{ statement }
39
+ end
40
+
41
+ for_symbol 'statement' do
42
+ matched %w{ matched }
43
+ unmatched %w{ unmatched }
44
+ if_statement_b " if ( expr ) { statements } ".split
45
+ if_else_statement_b " if ( expr ) { statements } else { statements } ".split
46
+ if_else_statement_b1 " if ( expr ) { statements } else statement ".split
47
+ end
48
+
49
+ for_symbol 'matched' do
50
+ if_else_statement0 " if ( expr ) ; else matched ".split
51
+ if_else_statement1 " if ( expr ) matched else matched ".split
52
+ if_else_statement3 " if ( expr ) matched else { statements } ".split
53
+ simple %w{ simple_statement }
54
+ end
55
+
56
+ for_symbol 'unmatched' do
57
+ if_statement0 " if ( expr ) matched ".split
58
+ if_statement1 " if ( expr ) unmatched ".split
59
+ if_else_statement2 " if ( expr ) matched else unmatched ".split
60
+ end
61
+
62
+ for_symbol 'block' do
63
+ empty_braces " { } ".split
64
+ braced_statements " { statements } ".split
65
+ end
66
+
67
+ for_symbol 'simple_statement' do
68
+ line_statement %w{ expr ; }
69
+ class_statement " class word { statements } ".split
70
+ class_extends_statement " class word extends word { statements } ".split
71
+
72
+ while_statement " while ( expr ) block ".split
73
+ do_while_statement " do block while ( expr ) ; ".split
74
+ for_statement " for ( expr ; expr ; expr ) block ".split
75
+ foreach_statement " foreach ( expr as expr ) block ".split
76
+ switch_case_statement " switch ( expr ) { case_statements } ".split
77
+ fun_define " function word ( fun_args ) { statements } ".split
78
+ protected_fun_define " protected function word ( fun_args ) { statements } ".split
79
+ private_fun_define " private function word ( fun_args ) { statements } ".split
80
+
81
+ static_declaration %w{ static variables ; }
82
+ global_declaration %w{ global variables ; }
83
+ class_protected_var_statement %w{ protected variable ; }
84
+ class_protected_w_default_stmt %w{ protected variable = expr ; }
85
+ class_var_statement %w{ var variable ; }
86
+ class_var_with_default_statement %w{ var variable = expr ; }
87
+ return_one %w{ return expr ; }
88
+ print_statement %w{ print expr ; }
89
+ echo_statement %w{ echo expr ; }
90
+ return_zero %w{ return ; }
91
+ break_statement %w{ break ; }
92
+ exit_call_statement %w{ exit ( ) ; }
93
+ exit_statement %w{ exit ; }
94
+ end
95
+
96
+ for_symbol 'elseif_statements' do
97
+ one_elseif %w{ elseif_statement }
98
+ multi_else_ifs %w{ elseif_statements elseif_statement }
99
+ end
100
+
101
+ for_symbol 'elseif_statement' do
102
+ else_if " else if ( expr ) block ".split
103
+ end
104
+
105
+ for_symbol 'case_statements' do
106
+ default_only_case %w{ default : statements }
107
+ one_case %w{ case expr : opt_statements }
108
+ default_case %w{ case_statements default : statements }
109
+ multi_case %w{ case_statements case expr : opt_statements }
110
+ end
111
+
112
+ for_symbol 'opt_statements' do
113
+ opt_multiple_statements %w{ statement statements }
114
+ opt_single_statement %w{ statement }
115
+ opt_no_statements %w{ }
116
+ end
117
+
118
+ for_symbol 'expr' do
119
+ # TODO: This one could get cleaned up
120
+ tertiary %w{ term ? expr : expr }
121
+ term_postop %w{ term postop }
122
+ post_increment_var %w{ term ++ }
123
+ post_decrement_var %w{ term -- }
124
+ reference_term %w{ & term }
125
+
126
+ term_or_expr %w{ term || expr }
127
+ term_or_expr_with_or %w{ term or expr }
128
+ term_and_expr %w{ term && expr }
129
+ term_boolean_and_expr %w{ term & expr }
130
+ term_and_expr_with_and %w{ term and expr }
131
+ term_not_equal_expr %w{ term <> expr }
132
+ term_less_than_expr %w{ term < expr }
133
+ term_greater_than_expr %w{ term > expr }
134
+
135
+ require_statement %w{ require expr }
136
+ require_once_statement %w{ require_once expr }
137
+ include_statement %w{ include expr }
138
+ include_once_statement %w{ include_once expr }
139
+
140
+ list_assign %w{ list ( fun_args ) = expr }
141
+
142
+ # oo_variable_variable_assign %w{ term -> variable = expr }
143
+ # oo_array_assign %w{ term -> word [ term ] = expr }
144
+
145
+ # term_array_append %w{ term [ ] = expr }
146
+ # term_array_assign %w{ term [ expr ] = expr }
147
+
148
+ # Unfortunately, I'm going to have to stuff everything
149
+ # inside this one statement.. so that others that I
150
+ # cannot predict can be parsed
151
+ term_assign %w{ term = expr }
152
+
153
+ term_concat_expr %w{ expr . term }
154
+ term_plus_expr %w{ expr + expr }
155
+ term_minus_expr %w{ expr - expr }
156
+ term_not_equals_expr %w{ expr != expr }
157
+ term_hashs_to_expr %w{ expr => expr }
158
+
159
+ term_op_expr %w{ term op expr }
160
+ term %w{ term }
161
+ end
162
+
163
+ for_symbol 'term' do
164
+ # TODO: This one could get cleaned up
165
+ number %w{ number }
166
+ false_value %w{ false }
167
+ true_value %w{ true }
168
+ a_string %w{ a_string }
169
+ a_variable %w{ variable }
170
+ class_method_call %w{ word :: word ( fun_call_args ) }
171
+
172
+ array_append %w{ term [ ] }
173
+ array_lookup %w{ term [ expr ] }
174
+ oo_variable %w{ term -> word }
175
+ oo_call %w{ term -> word ( fun_call_args ) }
176
+ oo_variable_variable %w{ term -> variable }
177
+
178
+ fun_call_trailing_comma %w{ word ( fun_call_args , ) }
179
+ regular_fun_call %w{ word ( fun_call_args ) }
180
+ var_call %w{ variable ( fun_call_args ) }
181
+ user_constant %w{ word }
182
+ new_object %w{ new word }
183
+ new_object_with_args %w{ new word ( fun_call_args ) }
184
+ new_variable_class_object %w{ new variable }
185
+ braced_lookup %w{ variable { expr } }
186
+
187
+ pre_increment_var %w{ ++ term }
188
+ pre_decrement_var %w{ -- term }
189
+ negative_var %w{ - term }
190
+ not_var %w{ ! term }
191
+
192
+ term_error_guard %w{ @ expr }
193
+
194
+ preop_term %w{ preop term }
195
+ paren_cast %w{ ( cast ) term }
196
+ paren_expr %w{ ( expr ) }
197
+ end
198
+
199
+ for_symbol 'a_string' do
200
+ composite_double_string %w{ open_double_quoted_string composite_string_nodes }
201
+ double_string %w{ double_quoted_string }
202
+ single_string %w{ single_quoted_string }
203
+ end
204
+
205
+ for_symbol 'composite_string_node' do
206
+ variable_within_string %w{ variable }
207
+ array_lookup_within_string %w{ array_lookup_node }
208
+ double_string_within_string %w{ double_quoted_string_node }
209
+ single_string_within_string %w{ single_quoted_string_node }
210
+ end
211
+
212
+ for_symbol 'composite_string_nodes' do
213
+ multiple_nodes %w{ composite_string_nodes composite_string_node }
214
+ single_node %w{ composite_string_node }
215
+ end
216
+
217
+ for_symbol 'variables' do
218
+ one_variable %w{ variable }
219
+ multiple_variables %w{ variables , variable }
220
+ end
221
+
222
+ for_symbol 'number' do
223
+ positive_number %w{ num }
224
+ signed_number %w{ op num }
225
+ end
226
+
227
+ for_symbol 'bracketed_expr' do
228
+ one_bracket %w{ single_bracket }
229
+ multi_brackets %w{ bracketed_expr single_bracket }
230
+ end
231
+
232
+ for_symbol 'oo_fun_call' do
233
+ oo_fun_call_trailing_comma %w{ word ( fun_call_args , ) }
234
+ oo_regular_fun_call %w{ word ( fun_call_args ) }
235
+ end
236
+
237
+ for_symbol 'fun_args' do
238
+ no_args %w{ }
239
+ single_arg %w{ expr }
240
+ multiple_args %w{ fun_args , expr }
241
+ end
242
+
243
+ for_symbol 'fun_args_within_call' do
244
+ no_args_within_call %w{ }
245
+ single_arg_within_call %w{ expr }
246
+ multiple_args_within_call %w{ fun_args_within_call , expr }
247
+ end
248
+
249
+ for_symbol 'fun_call_args' do
250
+ fun_args_within_call %w{ fun_args_within_call }
251
+ fun_args_with_trailing_comma %w{ fun_args_within_call , }
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+
258
+
259
+ my_filename = "lib/ionize/parser.rb"
260
+ compiled_filename = "lib/ionize/compiled_parser.rb"
261
+
262
+ if File.stat(my_filename).ctime > File.stat(compiled_filename).ctime
263
+ puts "Grammar newer than CompiledParser. Recompiling.."
264
+ null = Object.new.instance_eval do
265
+ def method_missing(*args, &blk); end
266
+ self
267
+ end
268
+ File.open("lib/ionize/compiled_parser.rb", "w+") do |f|
269
+ f.write(Dhaka::Parser.new(Ionize::Php::Grammar, null).compile_to_ruby_source_as("Ionize::Php::CompiledParser"))
270
+ end
271
+ end
272
+