electr 0.0.5 → 0.0.6
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 +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +77 -50
- data/bin/electr +1 -5
- data/electr.gemspec +1 -1
- data/lib/electr.rb +10 -9
- data/lib/electr/ast.rb +1 -0
- data/lib/electr/ast/ast.rb +1 -0
- data/lib/electr/ast/variable_ast.rb +13 -0
- data/lib/electr/compiler.rb +0 -1
- data/lib/electr/exceptions.rb +6 -0
- data/lib/electr/option.rb +2 -2
- data/lib/electr/parser/lexer.rb +2 -0
- data/lib/electr/parser/lexical_unit.rb +9 -0
- data/lib/electr/parser/rules/expression_rule.rb +17 -2
- data/lib/electr/parser/sya.rb +70 -11
- data/lib/electr/parser/token.rb +7 -2
- data/lib/electr/parser/tokenizer.rb +20 -4
- data/lib/electr/repl.rb +1 -0
- data/lib/electr/repl/electr_value.rb +78 -0
- data/lib/electr/repl/evaluator.rb +92 -7
- data/lib/electr/repl/printer.rb +26 -3
- data/lib/electr/version.rb +2 -2
- data/spec/compiler_spec.rb +62 -3
- data/spec/parser/lexer_spec.rb +5 -0
- data/spec/parser/sya_spec.rb +64 -0
- data/spec/parser/tokenizer_spec.rb +13 -0
- data/spec/repl/electr_value_spec.rb +86 -0
- data/spec/repl/evaluator_spec.rb +112 -3
- data/spec/repl/printer_spec.rb +42 -2
- data/spec/repl/repl_spec.rb +1 -1
- metadata +7 -6
- data/documentation/developer.md +0 -21
- data/documentation/grammar.md +0 -34
- data/documentation/precedence.md +0 -10
data/spec/parser/sya_spec.rb
CHANGED
@@ -68,6 +68,36 @@ describe Sya do
|
|
68
68
|
expect(sya.run).to eq [added, a, b]
|
69
69
|
end
|
70
70
|
|
71
|
+
specify 'R1 R2' do
|
72
|
+
a = LexicalUnit.variable('R1')
|
73
|
+
b = LexicalUnit.variable('R2')
|
74
|
+
added = LexicalUnit.operator('*')
|
75
|
+
sya = Sya.new([a, b])
|
76
|
+
|
77
|
+
# * R1 R2
|
78
|
+
expect(sya.run).to eq [added, a, b]
|
79
|
+
end
|
80
|
+
|
81
|
+
specify 'R1 5' do
|
82
|
+
a = LexicalUnit.variable('R1')
|
83
|
+
b = LexicalUnit.numeric('5')
|
84
|
+
added = LexicalUnit.operator('*')
|
85
|
+
sya = Sya.new([a, b])
|
86
|
+
|
87
|
+
# * R1 5
|
88
|
+
expect(sya.run).to eq [added, a, b]
|
89
|
+
end
|
90
|
+
|
91
|
+
specify '5 R1' do
|
92
|
+
a = LexicalUnit.numeric('5')
|
93
|
+
b = LexicalUnit.variable('R1')
|
94
|
+
added = LexicalUnit.operator('*')
|
95
|
+
sya = Sya.new([a, b])
|
96
|
+
|
97
|
+
# * R1 5
|
98
|
+
expect(sya.run).to eq [added, a, b]
|
99
|
+
end
|
100
|
+
|
71
101
|
specify 'sqrt(49) + 1' do
|
72
102
|
a = LexicalUnit.fname('sqrt')
|
73
103
|
b = LexicalUnit.open_parenthesis
|
@@ -185,4 +215,38 @@ describe Sya do
|
|
185
215
|
expect(sya.run).to eq [f, a, b, d, g]
|
186
216
|
end
|
187
217
|
|
218
|
+
specify "R1 = 100" do
|
219
|
+
a = LexicalUnit.variable("R1")
|
220
|
+
b = LexicalUnit.assign
|
221
|
+
c = LexicalUnit.numeric("100")
|
222
|
+
|
223
|
+
sya = Sya.new([a, b, c])
|
224
|
+
|
225
|
+
expect(sya.run).to eq [b, a, c]
|
226
|
+
end
|
227
|
+
|
228
|
+
specify "R1 = 200 + 100" do
|
229
|
+
a = LexicalUnit.variable("R1")
|
230
|
+
b = LexicalUnit.assign
|
231
|
+
c = LexicalUnit.numeric("200")
|
232
|
+
d = LexicalUnit.operator("+")
|
233
|
+
e = LexicalUnit.numeric("100")
|
234
|
+
|
235
|
+
sya = Sya.new([a, b, c, d, e])
|
236
|
+
|
237
|
+
expect(sya.run).to eq [b, a, d, c, e]
|
238
|
+
end
|
239
|
+
|
240
|
+
specify "R1 = R2 = 100" do
|
241
|
+
a = LexicalUnit.variable("R1")
|
242
|
+
b = LexicalUnit.assign
|
243
|
+
c = LexicalUnit.variable("R2")
|
244
|
+
d = LexicalUnit.assign
|
245
|
+
e = LexicalUnit.numeric("100")
|
246
|
+
|
247
|
+
sya = Sya.new([a, b, c, d, e])
|
248
|
+
|
249
|
+
expect(sya.run).to eq [b, a, d, c, e]
|
250
|
+
end
|
251
|
+
|
188
252
|
end
|
@@ -207,6 +207,19 @@ describe Tokenizer do
|
|
207
207
|
expect(tkr.next_token).to eq "2"
|
208
208
|
end
|
209
209
|
|
210
|
+
specify "R1" do
|
211
|
+
tkr = Tokenizer.new("R1")
|
212
|
+
expect(tkr.next_token).to eq "R1"
|
213
|
+
end
|
214
|
+
|
215
|
+
specify "R1 = 100" do
|
216
|
+
tkr = Tokenizer.new("R1 = 100")
|
217
|
+
|
218
|
+
expect(tkr.next_token).to eq "R1"
|
219
|
+
expect(tkr.next_token).to eq "="
|
220
|
+
expect(tkr.next_token).to eq "100"
|
221
|
+
end
|
222
|
+
|
210
223
|
it 'tokenize units and prefixes' do
|
211
224
|
units = %w( A Hz W C V F R Ω S ℧ H )
|
212
225
|
prefixes = %w( k M G T m μ u n p )
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Electr
|
4
|
+
|
5
|
+
describe ElectrValue do
|
6
|
+
|
7
|
+
describe "number" do
|
8
|
+
|
9
|
+
it "holds a number" do
|
10
|
+
result = ElectrValue.number(10)
|
11
|
+
expect(result.number).to eq 10
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has type number" do
|
15
|
+
result = ElectrValue.number(10)
|
16
|
+
expect(result.type).to eq :number
|
17
|
+
end
|
18
|
+
|
19
|
+
it "knows it is a number" do
|
20
|
+
result = ElectrValue.number(10)
|
21
|
+
expect(result.number?).to eq true
|
22
|
+
expect(result.error?).to eq false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "error" do
|
27
|
+
|
28
|
+
it "holds an error message" do
|
29
|
+
result = ElectrValue.error("message")
|
30
|
+
expect(result.error).to eq "message"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has type error" do
|
34
|
+
result = ElectrValue.error("message")
|
35
|
+
expect(result.type).to eq :error
|
36
|
+
end
|
37
|
+
|
38
|
+
it "knows it is a error" do
|
39
|
+
result = ElectrValue.error("message")
|
40
|
+
expect(result.error?).to eq true
|
41
|
+
expect(result.number?).to eq false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "hidden" do
|
46
|
+
|
47
|
+
it "holds a hidden number" do
|
48
|
+
result = ElectrValue.hidden(10)
|
49
|
+
expect(result.number).to eq 10
|
50
|
+
end
|
51
|
+
|
52
|
+
it "has type hidden" do
|
53
|
+
result = ElectrValue.hidden(10)
|
54
|
+
expect(result.type).to eq :hidden
|
55
|
+
end
|
56
|
+
|
57
|
+
it "knows it is a hidden number" do
|
58
|
+
result = ElectrValue.hidden(10)
|
59
|
+
expect(result.number?).to eq false
|
60
|
+
expect(result.hidden?).to eq true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "==" do
|
65
|
+
it "is equal when all same members" do
|
66
|
+
a = ElectrValue.number(10)
|
67
|
+
b = ElectrValue.number(10)
|
68
|
+
expect(a.object_id).not_to eq b.object_id
|
69
|
+
expect(a).to eq b
|
70
|
+
end
|
71
|
+
|
72
|
+
it "isn't equal when different types" do
|
73
|
+
a = ElectrValue.number(10)
|
74
|
+
b = ElectrValue.error("foo")
|
75
|
+
expect(a).not_to eq b
|
76
|
+
end
|
77
|
+
|
78
|
+
it "isn't equal when different classes" do
|
79
|
+
a = ElectrValue.number(10)
|
80
|
+
b = 10
|
81
|
+
expect(a).not_to eq b
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/spec/repl/evaluator_spec.rb
CHANGED
@@ -45,19 +45,128 @@ describe Evaluator do
|
|
45
45
|
evaluator = Evaluator.new
|
46
46
|
result = evaluator.evaluate_pn(pns)
|
47
47
|
|
48
|
-
expect(result).to eq code[:result]
|
48
|
+
expect(result).to eq ElectrValue.number(code[:result])
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
specify do
|
53
53
|
pns = Compiler.compile_to_pn("2 * 3")
|
54
|
-
|
54
|
+
|
55
55
|
evaluator = Evaluator.new
|
56
56
|
result = evaluator.evaluate_pn(pns)
|
57
57
|
|
58
|
-
expect(result).to eq 6
|
58
|
+
expect(result).to eq ElectrValue.number(6.0)
|
59
59
|
end
|
60
60
|
|
61
|
+
describe "environment" do
|
62
|
+
|
63
|
+
it "don't raise on unbound variable" do
|
64
|
+
evaluator = Evaluator.new
|
65
|
+
|
66
|
+
pns = Compiler.compile_to_pn("R1")
|
67
|
+
expect {
|
68
|
+
evaluator.evaluate_pn(pns)
|
69
|
+
}.not_to raise_error
|
70
|
+
end
|
71
|
+
|
72
|
+
it "evalutes an assignment" do
|
73
|
+
evaluator = Evaluator.new
|
74
|
+
|
75
|
+
pns = Compiler.compile_to_pn("R1 = 100")
|
76
|
+
result = evaluator.evaluate_pn(pns)
|
77
|
+
|
78
|
+
expect(result).to eq ElectrValue.hidden(100.0)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does chain assignment" do
|
82
|
+
evaluator = Evaluator.new
|
83
|
+
|
84
|
+
pns = Compiler.compile_to_pn("R1 = R2 = 100")
|
85
|
+
evaluator.evaluate_pn(pns)
|
86
|
+
|
87
|
+
expect(evaluator.environment["R1"]).to eq ElectrValue.number(100.0)
|
88
|
+
expect(evaluator.environment["R2"]).to eq ElectrValue.number(100.0)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "retains variable" do
|
92
|
+
evaluator = Evaluator.new
|
93
|
+
|
94
|
+
pns = Compiler.compile_to_pn("R1 = 100")
|
95
|
+
evaluator.evaluate_pn(pns)
|
96
|
+
expect(evaluator.environment["R1"]).to eq ElectrValue.number(100.0)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "starts empty" do
|
100
|
+
evaluator = Evaluator.new
|
101
|
+
expect(evaluator.environment).to be_empty
|
102
|
+
end
|
103
|
+
|
104
|
+
it "assigns an expression" do
|
105
|
+
evaluator = Evaluator.new
|
106
|
+
|
107
|
+
pns = Compiler.compile_to_pn("R2 = 10 + 7")
|
108
|
+
evaluator.evaluate_pn(pns)
|
109
|
+
expect(evaluator.environment["R2"]).to eq ElectrValue.number(17.0)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "assigns a variable's value" do
|
113
|
+
evaluator = Evaluator.new
|
114
|
+
|
115
|
+
pns = Compiler.compile_to_pn("R1 = 100")
|
116
|
+
evaluator.evaluate_pn(pns)
|
117
|
+
|
118
|
+
pns = Compiler.compile_to_pn("R2 = R1")
|
119
|
+
evaluator.evaluate_pn(pns)
|
120
|
+
expect(evaluator.environment["R2"]).to eq ElectrValue.number(100.0)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "gets the value" do
|
124
|
+
evaluator = Evaluator.new
|
125
|
+
|
126
|
+
pns = Compiler.compile_to_pn("R1 = 100")
|
127
|
+
evaluator.evaluate_pn(pns)
|
128
|
+
|
129
|
+
pns = Compiler.compile_to_pn("R1")
|
130
|
+
result = evaluator.evaluate_pn(pns)
|
131
|
+
expect(result).to eq ElectrValue.number(100.0)
|
61
132
|
|
133
|
+
end
|
134
|
+
|
135
|
+
it "can add two variables" do
|
136
|
+
evaluator = Evaluator.new
|
137
|
+
|
138
|
+
pns = Compiler.compile_to_pn("R1 = 100")
|
139
|
+
evaluator.evaluate_pn(pns)
|
140
|
+
|
141
|
+
pns = Compiler.compile_to_pn("R2 = 200")
|
142
|
+
evaluator.evaluate_pn(pns)
|
143
|
+
|
144
|
+
pns = Compiler.compile_to_pn("R1 + R2")
|
145
|
+
result = evaluator.evaluate_pn(pns)
|
146
|
+
expect(result).to eq ElectrValue.number(300.0)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "can add a variable and a numeric" do
|
150
|
+
evaluator = Evaluator.new
|
151
|
+
|
152
|
+
pns = Compiler.compile_to_pn("R1 = 100")
|
153
|
+
evaluator.evaluate_pn(pns)
|
154
|
+
|
155
|
+
pns = Compiler.compile_to_pn("R1 + 50")
|
156
|
+
result = evaluator.evaluate_pn(pns)
|
157
|
+
expect(result).to eq ElectrValue.number(150.0)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "can add a numeric and a variable" do
|
161
|
+
evaluator = Evaluator.new
|
162
|
+
|
163
|
+
pns = Compiler.compile_to_pn("R1 = 100")
|
164
|
+
evaluator.evaluate_pn(pns)
|
165
|
+
|
166
|
+
pns = Compiler.compile_to_pn("50 + R1")
|
167
|
+
result = evaluator.evaluate_pn(pns)
|
168
|
+
expect(result).to eq ElectrValue.number(150.0)
|
169
|
+
end
|
170
|
+
end
|
62
171
|
|
63
172
|
end
|
data/spec/repl/printer_spec.rb
CHANGED
@@ -6,12 +6,52 @@ describe Printer do
|
|
6
6
|
|
7
7
|
describe ".run" do
|
8
8
|
|
9
|
+
it 'accepts ElectrValue objects' do
|
10
|
+
expect {
|
11
|
+
|
12
|
+
Printer.run(ElectrValue.number(10.0))
|
13
|
+
|
14
|
+
}.not_to raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'accepts only ElectrValue objects' do
|
18
|
+
expect {
|
19
|
+
|
20
|
+
Printer.run(10.0)
|
21
|
+
|
22
|
+
}.to raise_error
|
23
|
+
end
|
24
|
+
|
9
25
|
it 'truncates integer like number' do
|
10
|
-
expect {
|
26
|
+
expect {
|
27
|
+
|
28
|
+
Printer.run(ElectrValue.number(10.0))
|
29
|
+
|
30
|
+
}.to output("10\n").to_stdout
|
11
31
|
end
|
12
32
|
|
13
33
|
it 'rounds number' do
|
14
|
-
expect {
|
34
|
+
expect {
|
35
|
+
|
36
|
+
Printer.run(ElectrValue.number(1.0 / 3))
|
37
|
+
|
38
|
+
}.to output("0.3333333333\n").to_stdout
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'display the error message if any' do
|
42
|
+
expect {
|
43
|
+
|
44
|
+
Printer.run(ElectrValue.error("foo"))
|
45
|
+
|
46
|
+
}.to output("foo\n").to_stdout
|
47
|
+
end
|
48
|
+
|
49
|
+
it "doesn't display a hidden value" do
|
50
|
+
expect {
|
51
|
+
|
52
|
+
Printer.run(ElectrValue.hidden(10))
|
53
|
+
|
54
|
+
}.to_not output.to_stdout
|
15
55
|
end
|
16
56
|
|
17
57
|
end
|
data/spec/repl/repl_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: electr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lkdjiin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -84,9 +84,6 @@ files:
|
|
84
84
|
- README.md
|
85
85
|
- Rakefile
|
86
86
|
- bin/electr
|
87
|
-
- documentation/developer.md
|
88
|
-
- documentation/grammar.md
|
89
|
-
- documentation/precedence.md
|
90
87
|
- electr.gemspec
|
91
88
|
- lib/electr.rb
|
92
89
|
- lib/electr/ast.rb
|
@@ -99,6 +96,7 @@ files:
|
|
99
96
|
- lib/electr/ast/operator_ast.rb
|
100
97
|
- lib/electr/ast/root_ast.rb
|
101
98
|
- lib/electr/ast/value_ast.rb
|
99
|
+
- lib/electr/ast/variable_ast.rb
|
102
100
|
- lib/electr/compiler.rb
|
103
101
|
- lib/electr/exceptions.rb
|
104
102
|
- lib/electr/option.rb
|
@@ -118,6 +116,7 @@ files:
|
|
118
116
|
- lib/electr/repl/ast_printer.rb
|
119
117
|
- lib/electr/repl/ast_reader.rb
|
120
118
|
- lib/electr/repl/base_reader.rb
|
119
|
+
- lib/electr/repl/electr_value.rb
|
121
120
|
- lib/electr/repl/eval_function.rb
|
122
121
|
- lib/electr/repl/evaluator.rb
|
123
122
|
- lib/electr/repl/nil_evaluator.rb
|
@@ -136,6 +135,7 @@ files:
|
|
136
135
|
- spec/parser/value_spec.rb
|
137
136
|
- spec/repl/ast_printer_spec.rb
|
138
137
|
- spec/repl/ast_reader_spec.rb
|
138
|
+
- spec/repl/electr_value_spec.rb
|
139
139
|
- spec/repl/evaluator_spec.rb
|
140
140
|
- spec/repl/nil_evaluator_spec.rb
|
141
141
|
- spec/repl/printer_spec.rb
|
@@ -165,7 +165,7 @@ rubyforge_project:
|
|
165
165
|
rubygems_version: 2.4.5
|
166
166
|
signing_key:
|
167
167
|
specification_version: 4
|
168
|
-
summary: Interactive language for electronic formulas
|
168
|
+
summary: Interactive tiny language for electronic formulas
|
169
169
|
test_files:
|
170
170
|
- spec/ast/ast_spec.rb
|
171
171
|
- spec/compiler_spec.rb
|
@@ -178,6 +178,7 @@ test_files:
|
|
178
178
|
- spec/parser/value_spec.rb
|
179
179
|
- spec/repl/ast_printer_spec.rb
|
180
180
|
- spec/repl/ast_reader_spec.rb
|
181
|
+
- spec/repl/electr_value_spec.rb
|
181
182
|
- spec/repl/evaluator_spec.rb
|
182
183
|
- spec/repl/nil_evaluator_spec.rb
|
183
184
|
- spec/repl/printer_spec.rb
|
data/documentation/developer.md
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
The parsing process
|
2
|
-
===================
|
3
|
-
|
4
|
-
The aim of the parsing process it to transform a source code into an AST.
|
5
|
-
|
6
|
-
AST: [Abstract Syntax Tree][AST]
|
7
|
-
|
8
|
-
SYA: [Shunting Yard Algorithm][SYA]
|
9
|
-
|
10
|
-
PN: [Prefix Notation][PN]
|
11
|
-
|
12
|
-
This is the stages of the parser:
|
13
|
-
|
14
|
-
1. Tokenizer
|
15
|
-
2. Lexer
|
16
|
-
3. Syntaxer
|
17
|
-
4. AST (using SYA for formulas)
|
18
|
-
|
19
|
-
[AST]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
|
20
|
-
[SYA]: https://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
21
|
-
[PN]: https://en.wikipedia.org/wiki/Polish_notation
|