frepl 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +120 -0
- data/Rakefile +15 -0
- data/bin/frepl +5 -0
- data/frepl.gemspec +29 -0
- data/lib/frepl.rb +81 -0
- data/lib/frepl/classifier.rb +190 -0
- data/lib/frepl/fortran_file.rb +159 -0
- data/lib/frepl/statement.rb +93 -0
- data/lib/frepl/statements/allocation.rb +9 -0
- data/lib/frepl/statements/assignment.rb +19 -0
- data/lib/frepl/statements/declaration.rb +47 -0
- data/lib/frepl/statements/derived_type.rb +29 -0
- data/lib/frepl/statements/do_loop.rb +17 -0
- data/lib/frepl/statements/execution.rb +7 -0
- data/lib/frepl/statements/function.rb +29 -0
- data/lib/frepl/statements/if_statement.rb +17 -0
- data/lib/frepl/statements/multi_declaration.rb +70 -0
- data/lib/frepl/statements/repl_command.rb +46 -0
- data/lib/frepl/statements/standalone_variable.rb +15 -0
- data/lib/frepl/statements/subroutine.rb +29 -0
- data/lib/frepl/statements/where.rb +17 -0
- data/lib/frepl/version.rb +3 -0
- data/spec/lib/frepl/assignment_spec.rb +53 -0
- data/spec/lib/frepl/classifier_spec.rb +171 -0
- data/spec/lib/frepl/declaration_spec.rb +193 -0
- data/spec/lib/frepl/function_spec.rb +43 -0
- data/spec/lib/frepl/multi_declaration_spec.rb +123 -0
- data/spec/lib/frepl/subroutine_spec.rb +46 -0
- data/spec/lib/frepl_spec.rb +256 -0
- data/spec/spec_helper.rb +106 -0
- metadata +186 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module Frepl
|
2
|
+
class ReplCommand < SinglelineStatement
|
3
|
+
COMMANDS = {
|
4
|
+
'run' => {
|
5
|
+
info: 'Run the current set of Fortran code',
|
6
|
+
l: lambda { |file| file.run },
|
7
|
+
},
|
8
|
+
'toggle_debug' => {
|
9
|
+
info: 'Toggle debug mode on/off',
|
10
|
+
l: lambda { |file| Frepl.debug = !Frepl.debug },
|
11
|
+
},
|
12
|
+
'help' => {
|
13
|
+
info: 'View this hopefully helpful help',
|
14
|
+
l: lambda do |file|
|
15
|
+
puts "Available Frepl commands:\n"
|
16
|
+
COMMANDS.each do |k, v|
|
17
|
+
puts "f:#{k} -- #{v[:info]}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
},
|
21
|
+
'z' => {
|
22
|
+
info: 'Undo last statement',
|
23
|
+
l: lambda do |file|
|
24
|
+
file.undo_last!
|
25
|
+
end
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
def accept(visitor)
|
30
|
+
visitor.visit_repl_command(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
def run(file)
|
34
|
+
Frepl.log("running: #{cmd}")
|
35
|
+
if COMMANDS.key?(cmd)
|
36
|
+
COMMANDS[cmd][:l].call(file)
|
37
|
+
else
|
38
|
+
puts "Unknown command: `#{cmd}`. Type `f:help` for list of commands."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def cmd
|
43
|
+
@cmd ||= line.match(/f:(.+)/)[1]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Frepl
|
2
|
+
class StandaloneVariable < SinglelineStatement
|
3
|
+
def variable_name
|
4
|
+
@variable_name ||= @line.match(Frepl::Classifier::VARIABLE_NAME_REGEX).to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
def accept(visitor)
|
8
|
+
visitor.visit_standalone_variable(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def expressionize
|
12
|
+
"write(*,*) #{variable_name}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Frepl
|
2
|
+
class Subroutine < MultilineStatement
|
3
|
+
def terminal_regex
|
4
|
+
/end subroutine\s?#{Frepl::Classifier::VARIABLE_NAME_REGEX}/
|
5
|
+
end
|
6
|
+
|
7
|
+
def accept(visitor)
|
8
|
+
visitor.visit_subroutine(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
@name ||= lines.first.match(Frepl::Classifier::SUBROUTINE_REGEX)[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
if other.is_a?(Subroutine)
|
17
|
+
self.name == other.name
|
18
|
+
else
|
19
|
+
super(other)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def starting_regex
|
26
|
+
Frepl::Classifier::SUBROUTINE_REGEX
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Frepl::Assignment do
|
4
|
+
let(:a) { Frepl::Assignment.new('a = 2') }
|
5
|
+
|
6
|
+
describe '#variable_name' do
|
7
|
+
subject { a.variable_name }
|
8
|
+
|
9
|
+
it 'extracts variable name from line' do
|
10
|
+
expect(subject).to eql('a')
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with no spacing' do
|
14
|
+
let(:a) { Frepl::Assignment.new('a=2') }
|
15
|
+
|
16
|
+
it 'extracts variable name from line' do
|
17
|
+
expect(subject).to eql('a')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with array' do
|
22
|
+
let(:a) { Frepl::Assignment.new('foobar = [1,2,3,4]') }
|
23
|
+
|
24
|
+
it 'extracts variable name from line' do
|
25
|
+
expect(subject).to eql('foobar')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#assigned_value' do
|
31
|
+
subject { a.assigned_value }
|
32
|
+
|
33
|
+
it 'extracts value' do
|
34
|
+
expect(subject).to eql('2')
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with no spacing' do
|
38
|
+
let(:a) { Frepl::Assignment.new('a=2') }
|
39
|
+
|
40
|
+
it 'extracts variable name from line' do
|
41
|
+
expect(subject).to eql('2')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with array' do
|
46
|
+
let(:a) { Frepl::Assignment.new('foobar = [1,2,3,4]') }
|
47
|
+
|
48
|
+
it 'extracts variable name from line' do
|
49
|
+
expect(subject).to eql('[1,2,3,4]')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Frepl::Classifier do
|
4
|
+
let(:classifier) { Frepl::Classifier.new }
|
5
|
+
describe '#classify' do
|
6
|
+
context 'single declaration with assignment' do
|
7
|
+
let(:line) { 'integer a' }
|
8
|
+
|
9
|
+
it 'returns a single declaration' do
|
10
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'single declaration with assignment' do
|
15
|
+
let(:line) { 'integer :: a = 1' }
|
16
|
+
|
17
|
+
it 'returns a single declaration' do
|
18
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'single real kind declaration with assignment' do
|
23
|
+
let(:line) { 'real(kind=4) :: a = 1.0' }
|
24
|
+
|
25
|
+
it 'returns a single declaration' do
|
26
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'parameter dp declaration' do
|
31
|
+
let(:line) { 'integer, parameter :: dp=kind(1.0d0)' }
|
32
|
+
|
33
|
+
it 'returns a single declaration' do
|
34
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'real declaration using dp parameter' do
|
39
|
+
let(:line) { 'real(kind=dp) fk' }
|
40
|
+
|
41
|
+
it 'returns a single declaration' do
|
42
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'single character declaration' do
|
47
|
+
let(:line) { 'character(len=4) name' }
|
48
|
+
|
49
|
+
it 'returns a single declaration' do
|
50
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'single character declaration with assignment' do
|
55
|
+
let(:line) { 'character(len=4) :: name = "john"' }
|
56
|
+
|
57
|
+
it 'returns a single declaration' do
|
58
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'single character declaration with assignment, without len' do
|
63
|
+
let(:line) { 'character(4) :: name = "john"' }
|
64
|
+
|
65
|
+
it 'returns a single declaration' do
|
66
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'single Fortran 2003 array declaration' do
|
71
|
+
let(:line) { 'integer, dimension(3) :: a = [1,2,3]' }
|
72
|
+
|
73
|
+
it 'returns a single declaration' do
|
74
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'single Fortran oldskool array declaration' do
|
79
|
+
let(:line) { 'integer, dimension(3) :: a = /1,2,3/' }
|
80
|
+
|
81
|
+
it 'returns a single declaration' do
|
82
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'logical declaration' do
|
87
|
+
let(:line) { 'logical :: somecond = .TRUE.' }
|
88
|
+
|
89
|
+
it 'returns a single declaration' do
|
90
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'multiple integer declaration' do
|
95
|
+
let(:line) { 'real :: a, b, c' }
|
96
|
+
|
97
|
+
it 'returns an multi declaration' do
|
98
|
+
expect(classifier.classify(line)).to be_a(Frepl::MultiDeclaration)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'multiple integer declaration with assignment' do
|
103
|
+
let(:line) { 'real :: a = 1, b, c=2' }
|
104
|
+
|
105
|
+
it 'returns an multi declaration' do
|
106
|
+
expect(classifier.classify(line)).to be_a(Frepl::MultiDeclaration)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'multiple array declaration' do
|
111
|
+
let(:line) { 'integer, dimension(3) :: a = [1,2,3], b = [1,2,3]' }
|
112
|
+
|
113
|
+
it 'returns a single declaration' do
|
114
|
+
expect(classifier.classify(line)).to be_a(Frepl::MultiDeclaration)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'lone variable name' do
|
119
|
+
let(:line) { 'foobar' }
|
120
|
+
|
121
|
+
it 'returns a standalone variable' do
|
122
|
+
expect(classifier.classify(line)).to be_a(Frepl::StandaloneVariable)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'start of if statement' do
|
127
|
+
let(:line) { 'if (9 < 10) then' }
|
128
|
+
|
129
|
+
it 'returns an IfStatement' do
|
130
|
+
expect(classifier.classify(line)).to be_a(Frepl::IfStatement)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'start of do loop' do
|
135
|
+
let(:line) { 'do i = 1, 3' }
|
136
|
+
|
137
|
+
it 'returns an DoLoop' do
|
138
|
+
expect(classifier.classify(line)).to be_a(Frepl::DoLoop)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'targetable array declaration' do
|
143
|
+
let(:line) { 'real, dimension(m,n), target :: A' }
|
144
|
+
|
145
|
+
it 'returns a single declaration' do
|
146
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'pointer array declaration' do
|
151
|
+
let(:line) { 'real, dimension(:), pointer:: A' }
|
152
|
+
|
153
|
+
it 'returns a single declaration' do
|
154
|
+
expect(classifier.classify(line)).to be_a(Frepl::Declaration)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'interruption' do
|
160
|
+
context 'in the middle of a multi-line statement' do
|
161
|
+
it 'should be able to be interrupted and start anew' do
|
162
|
+
classifier.classify('integer function add(a, b')
|
163
|
+
classifier.interrupt
|
164
|
+
classifier.classify('integer function sum(a, b')
|
165
|
+
classifier.classify('integer :: a, b')
|
166
|
+
classifier.classify('sum = a + b')
|
167
|
+
expect(classifier.classify('end function sum').complete?).to be true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Frepl::Declaration do
|
4
|
+
context 'simple declaration' do
|
5
|
+
let(:d) { Frepl::Declaration.new('integer a') }
|
6
|
+
|
7
|
+
it 'extracts variable name' do
|
8
|
+
expect(d.variable_name).to eq('a')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns nil value' do
|
12
|
+
expect(d.assigned_value).to eq(nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'extracts type' do
|
16
|
+
expect(d.type).to eq('integer')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'simple, double-colon' do
|
21
|
+
let(:d) { Frepl::Declaration.new('real :: a') }
|
22
|
+
|
23
|
+
it 'extracts variable name' do
|
24
|
+
expect(d.variable_name).to eq('a')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'has nil assigned value' do
|
28
|
+
expect(d.assigned_value).to be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'extracts type' do
|
32
|
+
expect(d.type).to eq('real')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'double-colon plus assignmentj' do
|
37
|
+
let(:d) { Frepl::Declaration.new('integer :: a = 3') }
|
38
|
+
|
39
|
+
it 'extracts variable name' do
|
40
|
+
expect(d.variable_name).to eq('a')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'has assigned value 3' do
|
44
|
+
expect(d.assigned_value).to eq('3')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'dimension plus assignment' do
|
49
|
+
let(:d) { Frepl::Declaration.new('integer, dimension(3) :: a = [1,2,3]') }
|
50
|
+
|
51
|
+
it 'extracts variable name' do
|
52
|
+
expect(d.variable_name).to eq('a')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'has assigned value [1,2,3]' do
|
56
|
+
expect(d.assigned_value).to eq('[1,2,3]')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'real with kind' do
|
61
|
+
let(:d) { Frepl::Declaration.new('real(kind=4) :: a = 2.3') }
|
62
|
+
|
63
|
+
it 'extracts variable name' do
|
64
|
+
expect(d.variable_name).to eq('a')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'has assigned value [1,2,3]' do
|
68
|
+
expect(d.assigned_value).to eq('2.3')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'has kind' do
|
72
|
+
expect(d.kind).to eq('4')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'real with kind' do
|
77
|
+
let(:d) { Frepl::Declaration.new('real(kind=4) :: a = 2.3') }
|
78
|
+
|
79
|
+
it 'extracts variable name' do
|
80
|
+
expect(d.variable_name).to eq('a')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'has assigned value [1,2,3]' do
|
84
|
+
expect(d.assigned_value).to eq('2.3')
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'has kind' do
|
88
|
+
expect(d.kind).to eq('4')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'logical' do
|
93
|
+
let(:d) { Frepl::Declaration.new('logical :: cond = .FALSE.') }
|
94
|
+
|
95
|
+
it 'extracts variable name' do
|
96
|
+
expect(d.variable_name).to eq('cond')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'has assigned value .FALSE.' do
|
100
|
+
expect(d.assigned_value).to eq('.FALSE.')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'character' do
|
105
|
+
context 'with len' do
|
106
|
+
let(:c) { Frepl::Declaration.new('character(len=4) :: name = "luke"') }
|
107
|
+
it 'extracts variable name' do
|
108
|
+
expect(c.variable_name).to eq('name')
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'has assigned value luke' do
|
112
|
+
expect(c.assigned_value).to eq('"luke"')
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'has len' do
|
116
|
+
expect(c.len).to eq('4')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'without len' do
|
121
|
+
let(:c) { Frepl::Declaration.new('character(4) :: name = "luke"') }
|
122
|
+
it 'extracts variable name' do
|
123
|
+
expect(c.variable_name).to eq('name')
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'has assigned value luke' do
|
127
|
+
expect(c.assigned_value).to eq('"luke"')
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'has len' do
|
131
|
+
expect(c.len).to eq('4')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'assignments designed to trick regex' do
|
136
|
+
it 'works with equals' do
|
137
|
+
d = Frepl::Declaration.new('character(4) :: x = "\'="')
|
138
|
+
expect(d.assigned_value).to eq('"\'="')
|
139
|
+
expect(d.len).to eq('4')
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'works with brackets' do
|
143
|
+
d = Frepl::Declaration.new('character(8) :: x = "]s\"')
|
144
|
+
expect(d.assigned_value).to eq('"]s\"')
|
145
|
+
expect(d.len).to eq('8')
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'works with spaces' do
|
149
|
+
d = Frepl::Declaration.new('character(len=7) :: x = "len= f"')
|
150
|
+
expect(d.assigned_value).to eq('"len= f"')
|
151
|
+
expect(d.len).to eq('7')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'targetable array' do
|
156
|
+
let(:c) { Frepl::Declaration.new('real, dimension(m,n), target :: A') }
|
157
|
+
|
158
|
+
it 'extracts variable name' do
|
159
|
+
expect(c.variable_name).to eq('A')
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'knows it is a pointer target' do
|
163
|
+
expect(c.target?).to be true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'pointer' do
|
168
|
+
let(:c) { Frepl::Declaration.new('real, dimension(:), pointer:: b') }
|
169
|
+
|
170
|
+
it 'extracts variable name' do
|
171
|
+
expect(c.variable_name).to eq('b')
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'knows it is a pointer' do
|
175
|
+
expect(c.pointer?).to be true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#==' do
|
181
|
+
let(:d) { Frepl::Declaration.new('integer a') }
|
182
|
+
|
183
|
+
context 'when other is a `Declaration`' do
|
184
|
+
let(:other_same) { Frepl::Declaration.new('real a') }
|
185
|
+
let(:other_diff) { Frepl::Declaration.new('integer b') }
|
186
|
+
|
187
|
+
it 'compares by variable name' do
|
188
|
+
expect(d).to eq(other_same)
|
189
|
+
expect(d).not_to eq(other_diff)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|