mumuki-prolog-runner 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 13d4e23a78247d40578287655fbd10a6ed83a2fd
4
+ data.tar.gz: 335636f3b50c7b702dc2e80538e13a10cb7b2a6b
5
+ SHA512:
6
+ metadata.gz: 08ac692949314e4641f3cc96718577fb776233e1c6fb4ad5240f0640fa444b9a0f59223039e080b696b5dd033edf05871eeff90e3c07793a952003b1cf4c9f23
7
+ data.tar.gz: 5ed272405a23dff488b813261ae7af1209b9ac805ffb84a21382f06a94b84bb3f6c3409325d8ef2a9ab22e11bc5d5a0888b11b2bac6ae83235e94619b953a249
@@ -0,0 +1,63 @@
1
+ require 'json'
2
+ require 'mumukit/inspection'
3
+
4
+ class Mumukit::Inspection::PlainInspection
5
+ def to_term
6
+ "inspection('#{type}')"
7
+ end
8
+ end
9
+
10
+ class Mumukit::Inspection::TargetedInspection
11
+ def to_term
12
+ "inspection('#{type}',#{Integer(target)})" rescue "inspection('#{type}','#{target}')"
13
+ end
14
+ end
15
+
16
+ class Mumukit::Inspection::NegatedInspection
17
+ def to_term
18
+ "not(#{@inspection.to_term})"
19
+ end
20
+ end
21
+
22
+ class PrologExpectationsHook < Mumukit::Templates::FileHook
23
+ isolated true
24
+
25
+ def command_line(filename)
26
+ "swipl -f #{filename} --quiet -t main 2>&1"
27
+ end
28
+
29
+ def compile_file_content(request)
30
+ ExpectationsFile.new(request).render
31
+ end
32
+
33
+ def post_process_file(file, result, status)
34
+ JSON.parse(result)['expectationResults'] rescue []
35
+ end
36
+ end
37
+
38
+ class ExpectationsFile
39
+ def initialize(request)
40
+ @content = request.content
41
+ @expectation_terms = self.class.expectations_to_terms(request.expectations)
42
+ end
43
+
44
+ def self.expectations_to_terms(expectations)
45
+ '[' + expectations.map do |e|
46
+ "expectation('#{e['binding']}',#{inspection_to_term(e['inspection'])})"
47
+ end.join(',') + ']'
48
+ end
49
+
50
+ def self.inspection_to_term(s)
51
+ Mumukit::Inspection.parse(s).to_term
52
+ end
53
+
54
+ def render
55
+ ERB.new(File.read(template_path)).result(binding)
56
+ end
57
+
58
+ private
59
+
60
+ def template_path
61
+ File.expand_path '../main.pl.erb', __FILE__
62
+ end
63
+ end
@@ -0,0 +1,71 @@
1
+ class PrologFeedbackHook < Mumukit::Hook
2
+ def run!(request, results)
3
+ content = request.content
4
+ test_results = results.test_results[0]
5
+
6
+ PrologExplainer.new.explain(content, test_results)
7
+ end
8
+
9
+ class PrologExplainer < Mumukit::Explainer
10
+ def explain_wrong_distinct_operator(content, _)
11
+ (/.{0,9}(\/=|<>|!=).{0,9}/.match content).try do |it|
12
+ {near: it[0]}
13
+ end
14
+ end
15
+
16
+ def explain_wrong_gte_operator(content, _)
17
+ (/.{0,9}(=>).{0,9}/.match content).try do |it|
18
+ {near: it[0]}
19
+ end
20
+ end
21
+
22
+ def explain_wrong_lte_operator(content, _)
23
+ (/.{0,9}(<=).{0,9}/.match content).try do |it|
24
+ {near: it[0]}
25
+ end
26
+ end
27
+
28
+
29
+ def explain_clauses_not_together(_, test_results)
30
+ (/Clauses of .*:(.*) are not together in the source-file/.match test_results).try do |it|
31
+ {target: it[1]}
32
+ end
33
+ end
34
+
35
+ def explain_singleton_variables(_, test_results)
36
+ (/Singleton variables: \[(.*)\]/.match test_results).try do |it|
37
+ {target: it[1]}
38
+ end
39
+ end
40
+
41
+ def explain_test_failed(_, test_results)
42
+ /test (.*): failed/ =~ test_results
43
+ end
44
+
45
+ def explain_not_sufficiently_instantiated(_, test_results)
46
+ (/received error: (.*): Arguments are not sufficiently instantiated/.match test_results).try do |it|
47
+ {target: it[1]}
48
+ end
49
+ end
50
+
51
+ def explain_operator_error(_, test_results)
52
+ /ERROR: (.*): Syntax error: Operator expected/ =~ test_results
53
+ end
54
+
55
+ def explain_missing_dot_error(_, test_results)
56
+ /ERROR: (.*): Syntax error: Operator priority clash/ =~ test_results
57
+ end
58
+
59
+
60
+ def explain_wrong_comma(_, test_results)
61
+ /ERROR: (.*): Full stop in clause-body\? Cannot redefine ,\/2/ =~ test_results
62
+ end
63
+
64
+ def explain_missing_predicate(_, test_results)
65
+ (/.*:(.*): Undefined procedure: .*:(.*)/.match test_results).try do |it|
66
+ {target: it[1],
67
+ missing: it[2]} unless it[1].include? 'unit body'
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/main.pl.erb ADDED
@@ -0,0 +1,107 @@
1
+ run_expectations(Expectations, Results) :-
2
+ maplist(run_expectation, Expectations, Results).
3
+
4
+ run_expectation(Expectation, result(Expectation, Result)) :- eval_expectation(Expectation,Result).
5
+
6
+ eval_expectation(expectation(Binding, Inspection), true) :-
7
+ call_expectation(Binding, Inspection), !.
8
+ eval_expectation(_, false).
9
+
10
+ call_expectation(Binding, inspection('HasBinding')) :-
11
+ usesPredicate(pred(Binding, _), _).
12
+ call_expectation(Binding, inspection('HasForall')) :-
13
+ hasForall(pred(Binding, _)).
14
+ call_expectation(Binding, inspection('HasFindall')) :-
15
+ hasFindall(pred(Binding, _)).
16
+ call_expectation(Binding, inspection('HasNot')) :-
17
+ hasNot(pred(Binding, _)).
18
+ call_expectation(Binding, inspection('HasUsage', Other)) :-
19
+ usesPredicate(pred(Binding, _), pred(Other, _)).
20
+ call_expectation(Binding, inspection('HasDirectRecursion')) :-
21
+ recursive(pred(Binding, _)).
22
+ call_expectation(Binding, inspection('HasArity', Arity)) :-
23
+ usesPredicate(pred(Binding, Arity), _).
24
+ call_expectation(Binding, not(Inspection)) :-
25
+ \+ call_expectation(Binding, Inspection).
26
+ call_expectation(Binding, inspection('HasCut')) :-
27
+ hasCut(pred(Binding, _)).
28
+
29
+ <%= @content %>
30
+
31
+ predToHead(pred(PredicateName, Arity), Head) :-
32
+ between(0, 9, Arity),
33
+ functor(Head, PredicateName, Arity).
34
+
35
+ clauseElements(Predicate, Elements):-
36
+ predToHead(Predicate, Head),
37
+ clause(Head, Clause),
38
+ clauseToList(Clause, Elements).
39
+
40
+ clauseToList((A,B), [A | BToList]):- clauseToList(B, BToList).
41
+ clauseToList(A, [A]):- functor(A,Name,_), Name \= (',').
42
+
43
+ usesPredicate(Predicate, UsedPredicate):-
44
+ clauseElements(Predicate, Elements),
45
+ member(ClauseElement, Elements),
46
+ isOrContains(ClauseElement, UsedPredicate).
47
+
48
+ isOrContains(ClauseElement, Predicate):- predToHead(Predicate, ClauseElement).
49
+ isOrContains(ClauseElement, Predicate):-
50
+ ClauseElement =.. [_|Args],
51
+ member(Arg, Args),
52
+ not(var(Arg)),
53
+ isOrContains(Arg, Predicate).
54
+
55
+ %% This would require a parametrized expectation
56
+ numberOfClauses(Predicate, Amount):-
57
+ predToHead(Predicate, Head),
58
+ findall(_,clause(Head,_), Clauses),
59
+ length(Clauses, Amount).
60
+
61
+ recursive(Predicate):-
62
+ usesPredicate(Predicate, Predicate).
63
+
64
+ hasForall(Predicate):-
65
+ usesPredicate(Predicate, pred(forall,2)).
66
+
67
+ hasNot(Predicate):-
68
+ usesPredicate(Predicate, pred(not,1)).
69
+
70
+ hasFindall(Predicate):-
71
+ usesPredicate(Predicate, pred(findall,3)).
72
+
73
+ hasCut(Predicate):-
74
+ usesPredicate(Predicate, pred(!,0)).
75
+
76
+
77
+ main(_) :-
78
+ Expectations = <%= @expectation_terms %>,
79
+ run_expectations(Expectations, Results),
80
+ write_json(Results).
81
+
82
+ write_json(Results) :-
83
+ write('{"expectationResults":['),
84
+ write_results(Results),
85
+ write(']}').
86
+
87
+ write_results([]).
88
+ write_results([X1]) :-
89
+ write_result(X1).
90
+ write_results([X1,X2|Xs]) :-
91
+ write_result(X1),
92
+ write(','),
93
+ write_results([X2|Xs]).
94
+
95
+ write_result(result(expectation(Binding, Inspection), Result)) :-
96
+ swrite_inspection(Inspection, SInspection),
97
+ writef('{"expectation":{"binding":"%w", "inspection":"%w"},"result":%w}',
98
+ [Binding, SInspection, Result]).
99
+
100
+ swrite_inspection(inspection(X), S) :-
101
+ swritef(S, "%w", [X]).
102
+ swrite_inspection(inspection(X, Y), S) :-
103
+ swritef(S, "%w:%w", [X, Y]).
104
+ swrite_inspection(not(Inspection), S2) :-
105
+ swrite_inspection(Inspection, S1),
106
+ swritef(S2, "Not:%w", [S1]).
107
+
@@ -0,0 +1,16 @@
1
+ class PrologMetadataHook < Mumukit::Hook
2
+ def metadata
3
+ {language: {
4
+ name: 'prolog',
5
+ icon: {type: 'devicon', name: 'prolog'},
6
+ version: 'swi-prolog 6.6.4',
7
+ extension: 'pl',
8
+ ace_mode: 'prolog',
9
+ prompt: '?'
10
+ },
11
+ test_framework: {
12
+ name: 'plunit',
13
+ test_extension: 'pl'
14
+ }}
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ require 'i18n'
2
+
3
+ I18n.load_path += Dir[File.join('.', 'locales', '*.yml')]
4
+
5
+ require 'mumukit'
6
+
7
+ Mumukit.runner_name = 'prolog'
8
+ Mumukit.configure do |config|
9
+ config.docker_image = 'mumuki/mumuki-plunit-worker'
10
+ config.content_type = 'markdown'
11
+ end
12
+
13
+ require_relative 'test_hook'
14
+ require_relative 'query_hook'
15
+ require_relative 'expectations_hook'
16
+ require_relative 'metadata_hook'
17
+ require_relative 'feedback_hook'
18
+
19
+
data/lib/query_hook.rb ADDED
@@ -0,0 +1,79 @@
1
+ class PrologQueryHook < Mumukit::Templates::FileHook
2
+ isolated true
3
+
4
+ def command_line(filename)
5
+ "swipl -f #{filename} --quiet -t main 2>&1"
6
+ end
7
+
8
+ def compile_file_content(req)
9
+ <<PROLOG
10
+ #{req.extra}
11
+ #{req.content}
12
+
13
+ main(_):-
14
+ run_query('#{req.query.gsub('\\', '\\' * 3 )}').
15
+
16
+ run_query(Query):-
17
+ catch(findall(Result, (atom_to_term(Query, Term, Result), Term), ResultSet),
18
+ error(TypeError,_),
19
+ (handleQueryError(TypeError, Query), halt(100)) ),
20
+ prettyWriteResultSet(ResultSet).
21
+
22
+ handleQueryError(type_error(callable,_), Query):-
23
+ writef('ERROR: run_query/1: Expected Callable predicate but instead got %w\\n', [Query]).
24
+
25
+ handleQueryError(syntax_error(TypeSyntaxError), Query):-
26
+ writef('ERROR: run_query/1: Syntax Error: %w in %w\\n', [TypeSyntaxError, Query]).
27
+
28
+ handleQueryError(signal(_,Number), _):-
29
+ SignalStatus is 128 + Number,
30
+ halt(SignalStatus).
31
+
32
+ handleQueryError(GeneralError, Query):-
33
+ writef('ERROR: run_query/1: %w in \\'%w\\'\\n', [GeneralError, Query]).
34
+
35
+ prettyWriteResultSet([]):-
36
+ writeln('no.').
37
+
38
+ prettyWriteResultSet([OneResult]):-
39
+ prettyWriteOneResult(OneResult),
40
+ writeln('.').
41
+
42
+ prettyWriteResultSet([OneResult | ResultSet]):-
43
+ ResultSet \\= [],
44
+ prettyWriteOneResult(OneResult),
45
+ writeln(' ;'),
46
+ prettyWriteResultSet(ResultSet).
47
+
48
+ prettyWriteOneResult([]):-
49
+ write('yes').
50
+
51
+ prettyWriteOneResult([OneBinding]):-
52
+ writeBinding(OneBinding).
53
+
54
+ prettyWriteOneResult([OneBinding | OneResult]):-
55
+ OneResult \\= [],
56
+ writeBinding(OneBinding),
57
+ writeln(','),
58
+ prettyWriteOneResult(OneResult).
59
+
60
+ writeBinding(OneBinding):-
61
+ OneBinding=..[(=), VarName, Value],
62
+ writef('%w = %w', [VarName, Value]).
63
+
64
+ writeBinding(NotABinding):-
65
+ not(NotABinding=..[(=) | _ ]),
66
+ writef('ERROR: writeBinding/1: Expected Binding, but no equals was found in: %w\\n', [NotABinding]),
67
+ halt(101).
68
+
69
+ PROLOG
70
+ end
71
+
72
+ end
73
+
74
+
75
+
76
+
77
+
78
+
79
+
data/lib/test_hook.rb ADDED
@@ -0,0 +1,31 @@
1
+ class PrologTestHook < Mumukit::Templates::FileHook
2
+ isolated true
3
+
4
+ def post_process_file(file, result, status)
5
+ if /ERROR: #{file.path}:.*: Syntax error: .*/ =~ result
6
+ [format_code(result), :failed]
7
+ elsif /Caught signal 24 \(xcpu\)/ =~ result
8
+ [format_code(I18n.t(:time_exceeded)), :failed]
9
+ else
10
+ [format_code(result), status]
11
+ end
12
+ end
13
+
14
+ def command_line(filename)
15
+ "swipl -f #{filename} --quiet -t run_tests 2>&1"
16
+ end
17
+
18
+ def format_code(code)
19
+ "```\n#{code}\n```"
20
+ end
21
+
22
+ def compile_file_content(request)
23
+ <<EOF
24
+ :- begin_tests(mumuki_submission_test, []).
25
+ #{request.test}
26
+ #{request.content}
27
+ #{request.extra}
28
+ :- end_tests(mumuki_submission_test).
29
+ EOF
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mumuki-prolog-runner
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Franco Leonardo Bulgarelli
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-09-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mumukit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: codeclimate-test-reporter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mumukit-bridge
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ description:
98
+ email:
99
+ - franco@mumuki.org
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - lib/expectations_hook.rb
105
+ - lib/feedback_hook.rb
106
+ - lib/main.pl.erb
107
+ - lib/metadata_hook.rb
108
+ - lib/prolog_runner.rb
109
+ - lib/query_hook.rb
110
+ - lib/test_hook.rb
111
+ homepage: http://github.com/mumuki/mumuki-prolog-server
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.4.8
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Prolog Runner for Mumuki
135
+ test_files: []