farleyknight-ionize 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|