farleyknight-ionize 0.1.0
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.rdoc +59 -0
- data/Rakefile +5 -0
- data/bin/ionize +47 -0
- data/lib/ionize.rb +75 -0
- data/lib/ionize/environment.rb +56 -0
- data/lib/ionize/environment/application.rb +58 -0
- data/lib/ionize/environment/php_array.rb +95 -0
- data/lib/ionize/parser.rb +272 -0
- data/lib/ionize/tokenizer.rb +544 -0
- data/lib/ionize/translate.rb +34 -0
- data/lib/ionize/translate/composite_string_statements.rb +79 -0
- data/lib/ionize/translate/debug.rb +16 -0
- data/lib/ionize/translate/ext.rb +47 -0
- data/lib/ionize/translate/function_args.rb +132 -0
- data/lib/ionize/translate/if_statements.rb +42 -0
- data/lib/ionize/translate/multiple_statements.rb +22 -0
- data/lib/ionize/translate/php_to_ruby.rb +40 -0
- data/lib/ionize/translate/rails_for_php.rb +191 -0
- data/lib/ionize/translate/rewritable.rb +133 -0
- data/lib/ionize/translate/rewrites.rb +51 -0
- data/lib/ionize/translate/statements.rb +622 -0
- data/lib/ionize/translate/switch_case_statements.rb +52 -0
- data/lib/ionize/translate/term_statements.rb +76 -0
- data/lib/ionize/translate/translator.rb +52 -0
- data/lib/ionize/version.rb +9 -0
- data/spec/fixtures/array_lookup.php +10 -0
- data/spec/fixtures/boolean_operators.php +5 -0
- data/spec/fixtures/boolean_operators.rb +6 -0
- data/spec/fixtures/class_def.php +34 -0
- data/spec/fixtures/class_def.rb +34 -0
- data/spec/fixtures/dangling_else.php +8 -0
- data/spec/fixtures/dangling_else.rb +12 -0
- data/spec/fixtures/drupal_1.php +663 -0
- data/spec/fixtures/drupal_2.php +1152 -0
- data/spec/fixtures/empty_string.php +12 -0
- data/spec/fixtures/for_loop.php +17 -0
- data/spec/fixtures/for_loop2.php +13 -0
- data/spec/fixtures/for_loop3.php +16 -0
- data/spec/fixtures/for_loop3.rb +17 -0
- data/spec/fixtures/for_loop4.php +5 -0
- data/spec/fixtures/for_loop4.rb +6 -0
- data/spec/fixtures/foreach.php +9 -0
- data/spec/fixtures/foreach2.php +8 -0
- data/spec/fixtures/foreach3.php +7 -0
- data/spec/fixtures/foreach3.rb +7 -0
- data/spec/fixtures/fun_def.php +9 -0
- data/spec/fixtures/fun_def2.php +30 -0
- data/spec/fixtures/fun_def2.rb +30 -0
- data/spec/fixtures/fun_def3.php +33 -0
- data/spec/fixtures/fun_def4.php +43 -0
- data/spec/fixtures/fun_def4.rb +37 -0
- data/spec/fixtures/fun_def5.php +36 -0
- data/spec/fixtures/fun_with_if.php +6 -0
- data/spec/fixtures/fun_with_if.rb +6 -0
- data/spec/fixtures/fun_with_ifs.php +12 -0
- data/spec/fixtures/fun_with_ifs.rb +14 -0
- data/spec/fixtures/hello_world.php +6 -0
- data/spec/fixtures/heredoc.php +6 -0
- data/spec/fixtures/heredoc.rb +5 -0
- data/spec/fixtures/if.php +6 -0
- data/spec/fixtures/if.rb +7 -0
- data/spec/fixtures/if_boolean.php +5 -0
- data/spec/fixtures/if_boolean.rb +5 -0
- data/spec/fixtures/if_else.php +11 -0
- data/spec/fixtures/if_else1.php +17 -0
- data/spec/fixtures/if_else2.php +8 -0
- data/spec/fixtures/if_else3.php +15 -0
- data/spec/fixtures/if_else_nested.php +14 -0
- data/spec/fixtures/if_else_nested.rb +15 -0
- data/spec/fixtures/if_else_series.php +12 -0
- data/spec/fixtures/if_else_series.rb +12 -0
- data/spec/fixtures/if_not.php +5 -0
- data/spec/fixtures/if_not.rb +5 -0
- data/spec/fixtures/if_with_brackets.php +7 -0
- data/spec/fixtures/if_with_brackets.rb +7 -0
- data/spec/fixtures/long_if_else.php +10 -0
- data/spec/fixtures/long_if_else.rb +9 -0
- data/spec/fixtures/oo.php +16 -0
- data/spec/fixtures/php_nuke/sql_layer.php +527 -0
- data/spec/fixtures/postop.php +3 -0
- data/spec/fixtures/preop.php +7 -0
- data/spec/fixtures/simple_fun_def.php +4 -0
- data/spec/fixtures/switch_case.php +13 -0
- data/spec/fixtures/switch_case.rb +14 -0
- data/spec/fixtures/switch_case2.php +25 -0
- data/spec/fixtures/switch_case3.php +40 -0
- data/spec/fixtures/switch_case3.rb +42 -0
- data/spec/fixtures/switch_case4.php +56 -0
- data/spec/fixtures/switch_case5.php +71 -0
- data/spec/fixtures/switch_case_with_rescue_nil.php +43 -0
- data/spec/fixtures/switch_case_with_rescue_nil.rb +35 -0
- data/spec/fixtures/tertiary.php +3 -0
- data/spec/helper.rb +17 -0
- data/spec/php_environment_spec.rb +83 -0
- data/spec/php_parser_spec.rb +121 -0
- data/spec/php_translator_spec.rb +358 -0
- data/spec/rails_for_php_spec.rb +303 -0
- metadata +191 -0
data/README.rdoc
ADDED
@@ -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.
|
data/Rakefile
ADDED
data/bin/ionize
ADDED
@@ -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
|
data/lib/ionize.rb
ADDED
@@ -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
|
+
|