mulang-php 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,15 @@
1
+ [![Build Status](https://travis-ci.org/mumuki/mulang-php.svg?branch=master)](https://travis-ci.org/mumuki/mulang-php)
2
+ [![Code Climate](https://codeclimate.com/github/mumuki/mulang-php/badges/gpa.svg)](https://codeclimate.com/github/mumuki/mulang-php)
3
+ [![Test Coverage](https://codeclimate.com/github/mumuki/mulang-php/badges/coverage.svg)](https://codeclimate.com/github/mumuki/mulang-php)
4
+
5
+ # Mulang::PHP
6
+
7
+ ## Contributing
8
+
9
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mumuki/mulang-php. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
10
+
11
+
12
+ ## License
13
+
14
+ The gem is available as open source under the terms of the [GPLv3](http://opensource.org/licenses/gpl-license).
15
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/.gitkeep ADDED
File without changes
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mulang/php"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ #require "irb"
14
+ #IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/mulang/php.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'ast'
2
+ require 'parser/current'
3
+ require 'mumukit/core'
4
+
5
+ require_relative "./php/version"
6
+
7
+ module Mulang
8
+ module PHP
9
+ def self.parse(php_ast)
10
+ Mulang::PHP::AstProcessor.new.process_block php_ast
11
+ end
12
+
13
+ def self.language
14
+ Mumukit::Language::External.new { |it| parse(it) }
15
+ end
16
+ end
17
+ end
18
+
19
+ require_relative "./php/sexp"
20
+ require_relative './php/ast_processor'
@@ -0,0 +1,271 @@
1
+ module Mulang::PHP
2
+ class AstProcessor
3
+ include AST::Sexp
4
+ include Mulang::PHP::Sexp
5
+
6
+ def initialize
7
+ define_binary_operators!
8
+ end
9
+
10
+ def process_block(stmts)
11
+ sequence *process(stmts)
12
+ end
13
+
14
+ def process(node)
15
+ return ms(:None) if node.nil?
16
+
17
+ if node.is_a?(Array)
18
+ return node.map { |it| process it }
19
+ end
20
+
21
+ if node.is_a?(Hash)
22
+ return send "on_#{node[:nodeType]}", node
23
+ end
24
+
25
+ ms(:Other)
26
+ end
27
+
28
+ def process_array(array, &f)
29
+ array.map f
30
+ end
31
+
32
+ def get_name(node)
33
+ node[:parts].first
34
+ end
35
+
36
+ def define_binary_operators!
37
+ [
38
+ { token: '===', name: 'Identical', supports_assign?: false },
39
+ { token: '!==', name: 'NotIdentical', supports_assign?: false },
40
+ { token: '.', name: 'Concat', supports_assign?: true },
41
+ { token: '+', name: 'Plus', supports_assign?: true },
42
+ { token: '-', name: 'Minus', supports_assign?: true },
43
+ { token: '*', name: 'Mul', supports_assign?: true },
44
+ { token: '/', name: 'Div', supports_assign?: true },
45
+ { token: '%', name: 'Mod', supports_assign?: true },
46
+ { token: '**', name: 'Pow', supports_assign?: true },
47
+ { token: '>', name: 'Greater', supports_assign?: false },
48
+ { token: '<', name: 'Smaller', supports_assign?: false },
49
+ { token: '>=', name: 'GreaterOrEqual', supports_assign?: false },
50
+ { token: '<=', name: 'SmallerOrEqual', supports_assign?: false },
51
+ { token: '&', name: 'BitwiseAnd', supports_assign?: true },
52
+ { token: '|', name: 'BitwiseOr', supports_assign?: true },
53
+ { token: '&&', name: 'BooleanAnd', supports_assign?: false },
54
+ { token: '||', name: 'BooleanOr', supports_assign?: false },
55
+ { token: 'and', name: 'LogicalAnd', supports_assign?: false },
56
+ { token: 'or', name: 'LogicalOr', supports_assign?: false },
57
+ { token: 'xor', name: 'LogicalXOr', supports_assign?: false }
58
+ ].each { |it|
59
+ self.class.redefine_method(:"on_Expr_BinaryOp_#{it[:name]}") { |node|
60
+ process_binary_operator it[:token], node
61
+ }
62
+
63
+ if it[:supports_assign?]
64
+ self.class.redefine_method(:"on_Expr_AssignOp_#{it[:name]}") { |node|
65
+ binary_operator "#{it[:token]}=", process(node[:var]), process(node[:expr])
66
+ }
67
+ end
68
+ }
69
+ end
70
+
71
+ def process_binary_operator(operator, node)
72
+ binary_operator operator, process(node[:left]), process(node[:right])
73
+ end
74
+
75
+ # ---
76
+
77
+ # VALUES
78
+
79
+ def on_Stmt_Expression(node)
80
+ process node[:expr]
81
+ end
82
+
83
+ def on_Expr_Variable(node)
84
+ ms :Reference, node[:name]
85
+ end
86
+
87
+ def on_Scalar_DNumber(node)
88
+ ms :MuNumber, node[:value]
89
+ end
90
+ alias on_Scalar_LNumber on_Scalar_DNumber
91
+
92
+ def on_Scalar_String(node)
93
+ ms :MuString, node[:value]
94
+ end
95
+
96
+ def on_Expr_ConstFetch(node)
97
+ value = get_name(node[:name]).downcase
98
+
99
+ case value
100
+ when 'true'
101
+ ms :MuBool, true
102
+ when 'false'
103
+ ms :MuBool, false
104
+ when 'null'
105
+ ms :None
106
+ else
107
+ ms :Reference, value
108
+ end
109
+ end
110
+
111
+ def on_Expr_Array(node)
112
+ items = node[:items]
113
+ is_array = items.all? { |it| it[:key].nil? }
114
+
115
+ is_array ? ms(:MuList, process(items))
116
+ : ms(:MuObject, process_block(items))
117
+ end
118
+
119
+ def on_Expr_ArrayItem(node)
120
+ value = process(node[:value])
121
+
122
+ node[:key] ? ms(:Attribute, node[:key][:value].to_s, value)
123
+ : value
124
+ end
125
+
126
+ def on_Expr_Closure(node)
127
+ ms :Lambda, process(node[:params]), process_block(node[:stmts])
128
+ end
129
+
130
+ def on_Param(node)
131
+ ms :VariablePattern, node[:var][:name]
132
+ end
133
+
134
+ # OPERATORS
135
+
136
+ def on_Expr_BinaryOp_Equal(node)
137
+ ms :Equal, [process(node[:left]), process(node[:right])]
138
+ end
139
+
140
+ def on_Expr_BinaryOp_NotEqual(node)
141
+ ms :NotEqual, [process(node[:left]), process(node[:right])]
142
+ end
143
+
144
+ def on_Expr_PostInc(node)
145
+ binary_operator '+', process(node[:var]), ms(:MuNumber, 1)
146
+ end
147
+ alias on_Expr_PreInc on_Expr_PostInc
148
+
149
+ def on_Expr_PostDec(node)
150
+ binary_operator '-', process(node[:var]), ms(:MuNumber, 1)
151
+ end
152
+ alias on_Expr_PreDec on_Expr_PostDec
153
+
154
+ # FUNCTION CALLS
155
+
156
+ def on_Expr_FuncCall(node)
157
+ application get_name(node[:name]), process(node[:args])
158
+ end
159
+
160
+ def on_Arg(node)
161
+ process node[:value]
162
+ end
163
+
164
+ # DECLARATIONS
165
+
166
+ def on_Stmt_Function(node)
167
+ simple_function node[:name][:name], process(node[:params]), process_block(node[:stmts])
168
+ end
169
+
170
+ def on_Stmt_Return(node)
171
+ ms :Return, process(node[:expr])
172
+ end
173
+
174
+ # STATEMENTS
175
+
176
+ def on_Expr_Assign(node)
177
+ left = node[:var]
178
+ exp = process(node[:expr])
179
+
180
+ if left[:nodeType] == 'Expr_PropertyFetch'
181
+ simple_send process(left[:var]), "#{left[:name][:name]}=", [exp]
182
+ else
183
+ ms :Assignment, left[:name], exp
184
+ end
185
+ end
186
+
187
+ def on_Stmt_Echo(node)
188
+ ms :Print, process_block(node[:exprs])
189
+ end
190
+
191
+ def on_Stmt_If(node)
192
+ condition = node[:cond]
193
+ body = node[:stmts]
194
+ else_block = node[:else]
195
+
196
+ ms :If, process(condition), process_block(body), process(else_block)
197
+ end
198
+ alias on_Stmt_ElseIf on_Stmt_If
199
+
200
+ def on_Stmt_Else(node)
201
+ process_block node[:stmts]
202
+ end
203
+
204
+ def on_Stmt_For(node)
205
+ ms :ForLoop, process_block(node[:init]), process_block(node[:cond]), process_block(node[:loop]), process_block(node[:stmts])
206
+ end
207
+
208
+ def on_Stmt_While(node)
209
+ ms :While, process(node[:cond]), process_block(node[:stmts])
210
+ end
211
+
212
+ def on_Stmt_Foreach(node)
213
+ ms :For, [ms(:Generator, ms(:VariablePattern, node[:valueVar][:name]), process(node[:expr]))], process_block(node[:stmts])
214
+ end
215
+
216
+ # OOP
217
+
218
+ def on_Expr_PropertyFetch(node)
219
+ simple_send process(node[:var]), node[:name][:name], []
220
+ end
221
+
222
+ def on_Expr_MethodCall(node)
223
+ simple_send process(node[:var]), node[:name][:name], process(node[:args])
224
+ end
225
+
226
+ def on_Expr_New(node)
227
+ ms :New, process(node[:class]), process(node[:args])
228
+ end
229
+
230
+ def on_Name(node)
231
+ ms :Reference, get_name(node)
232
+ end
233
+
234
+ def on_Stmt_Class(node)
235
+ superclass = node.dig(:extends, :parts)&.first
236
+ interfaces = node[:implements].map { |it| { nodeType: 'Stmt_Implement', name: get_name(it) } }
237
+
238
+ ms :Class, node[:name][:name], superclass, process_block(interfaces.concat(node[:stmts]))
239
+ end
240
+
241
+ def on_Stmt_Implement(node)
242
+ ms :Implement, ms(:Reference, node[:name])
243
+ end
244
+
245
+ def on_Stmt_Property(node)
246
+ prop = node[:props].first
247
+ ms :Attribute, prop[:name][:name], process(prop[:default])
248
+ end
249
+
250
+ def on_Stmt_ClassMethod(node)
251
+ name = node[:name][:name]
252
+ params = process(node[:params])
253
+
254
+ if node[:stmts].nil?
255
+ ms :TypeSignature, name, ms(:ParameterizedType, params.map { |it| 'Any' }, 'Any', [])
256
+ else
257
+ simple_method name, params, process_block(node[:stmts])
258
+ end
259
+ end
260
+
261
+ def on_Stmt_Interface(node)
262
+ parents = node[:extends].map { |it| get_name(it) }
263
+ ms :Interface, node[:name][:name], parents, process_block(node[:stmts])
264
+ end
265
+
266
+ def method_missing(m, *args, &block)
267
+ puts m, args
268
+ ms :Other, "#{m}: #{args.to_s}", nil
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,55 @@
1
+ module Mulang::PHP
2
+ module Sexp
3
+ def sequence(*contents)
4
+ if contents.empty?
5
+ ms(:None)
6
+ elsif contents.size == 1
7
+ contents[0]
8
+ else
9
+ ms(:Sequence, *contents)
10
+ end
11
+ end
12
+
13
+ def ms(tag, *contents)
14
+ if contents.empty?
15
+ {tag: tag}
16
+ elsif contents.size == 1
17
+ {tag: tag, contents: contents.first}
18
+ else
19
+ {tag: tag, contents: contents}
20
+ end
21
+ end
22
+
23
+ def simple_function(name, args, body)
24
+ callable :Function, name, args, body
25
+ end
26
+
27
+ def simple_method(name, args, body)
28
+ callable :Method, name, args, body
29
+ end
30
+
31
+ def callable(type, name, args, body)
32
+ {
33
+ tag: type,
34
+ contents: [
35
+ name,
36
+ [
37
+ [ args, {tag: :UnguardedBody, contents: body }]
38
+ ]
39
+ ]
40
+ }
41
+ end
42
+
43
+ def application(name, args)
44
+ ms :Application, [ms(:Reference, name), args]
45
+ end
46
+
47
+ def binary_operator(operator, left, right)
48
+ application operator, [left, right]
49
+ end
50
+
51
+ def simple_send(sender, message, args)
52
+ ms(:Send, sender, ms(:Reference, message), args)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ module Mulang
2
+ module PHP
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mulang/php/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mulang-php"
8
+ spec.version = Mulang::PHP::VERSION
9
+ spec.authors = ["Rodrigo Alfonso", "Franco Leonardo Bulgarelli"]
10
+ spec.email = ["rodri042@gmail.com", "franco@mumuki.org"]
11
+
12
+ spec.summary = "PHP integration for the Mulang Language Analyzer"
13
+ spec.description = "PHP - Mulang Parser"
14
+ spec.homepage = "https://mumuki.io"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.14"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "pry"
28
+
29
+ spec.add_dependency "parser"
30
+ spec.add_dependency "ast"
31
+ spec.add_dependency "mumukit-core", "~> 1.0"
32
+ spec.add_dependency "mulang", "~> 4.0"
33
+ end
metadata ADDED
@@ -0,0 +1,176 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mulang-php
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Rodrigo Alfonso
8
+ - Franco Leonardo Bulgarelli
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2018-08-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.14'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.14'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: pry
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: parser
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: ast
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: mumukit-core
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '1.0'
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '1.0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: mulang
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '4.0'
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '4.0'
126
+ description: PHP - Mulang Parser
127
+ email:
128
+ - rodri042@gmail.com
129
+ - franco@mumuki.org
130
+ executables: []
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - ".gitignore"
135
+ - ".rspec"
136
+ - ".ruby-version"
137
+ - ".travis.yml"
138
+ - CODE_OF_CONDUCT.md
139
+ - COPYRIGHT.txt
140
+ - Gemfile
141
+ - LICENSE.txt
142
+ - README.md
143
+ - Rakefile
144
+ - bin/.gitkeep
145
+ - bin/console
146
+ - bin/setup
147
+ - lib/mulang/php.rb
148
+ - lib/mulang/php/ast_processor.rb
149
+ - lib/mulang/php/sexp.rb
150
+ - lib/mulang/php/version.rb
151
+ - mulang-php.gemspec
152
+ homepage: https://mumuki.io
153
+ licenses:
154
+ - MIT
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.5.1
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: PHP integration for the Mulang Language Analyzer
176
+ test_files: []