electr 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +40 -19
- data/documentation/precedence.md +2 -0
- data/lib/electr.rb +12 -1
- data/lib/electr/option.rb +1 -1
- data/lib/electr/parser.rb +1 -0
- data/lib/electr/parser/lexical_unit.rb +1 -1
- data/lib/electr/parser/token.rb +1 -1
- data/lib/electr/parser/tokenizer.rb +5 -2
- data/lib/electr/parser/value.rb +64 -0
- data/lib/electr/repl/eval_function.rb +1 -1
- data/lib/electr/repl/repl.rb +1 -1
- data/lib/electr/version.rb +2 -1
- data/spec/parser/lexer_spec.rb +24 -0
- data/spec/parser/tokenizer_spec.rb +36 -0
- data/spec/parser/value_spec.rb +49 -0
- data/spec/repl/evaluator_spec.rb +4 -2
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86d47b60ef5f815792290a73257593f50f6819a1
|
4
|
+
data.tar.gz: 638a91fb8edea30cf2c782a972c21591efea09f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abdf7b5b3f6282134294825cfeeb277d5d2116573f90aa50e1fb4e836ca9b9d99dcee00fccee571225631f83a3e86e856f70c9a091151edcd304355c8b391354
|
7
|
+
data.tar.gz: 745e6f0654ab7fea487954ebd0f7443ac18471f89a084f7dca7860c2d332c6276b8d794899c96f951fe9b5b3f0fc3ebdedb077d45c681d43b044cd90ff2c07e8
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,17 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
5
5
|
|
6
6
|
## [Unreleased] - unreleased
|
7
7
|
|
8
|
+
## [0.0.5] - 2015-09-28
|
9
|
+
### Added
|
10
|
+
- All units and prefix used in electronic (sort of)
|
11
|
+
- One can use * for a multiplication as well as no symbol
|
12
|
+
- √ as an alias of sqrt
|
13
|
+
- The version now has a codename. The current one is «Units»
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
- A bug where some illegal tokens produced an infinite loop
|
17
|
+
|
18
|
+
|
8
19
|
## [0.0.4] - 2015-09-09
|
9
20
|
### Added
|
10
21
|
- Exponent operator: ^
|
data/README.md
CHANGED
@@ -95,22 +95,43 @@ is in Hertz.
|
|
95
95
|
E> 1 / (2 pi 0.5uF sqrt(11k 22k))
|
96
96
|
20.4617344581
|
97
97
|
|
98
|
-
### Units
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
Ω R
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
98
|
+
### Units, Prefixes and Abbreviations
|
99
|
+
|
100
|
+
Electr knows the following units:
|
101
|
+
|
102
|
+
Symbol | Name
|
103
|
+
:-----: | -----
|
104
|
+
A | ampere
|
105
|
+
Ω R | ohm
|
106
|
+
V | volt
|
107
|
+
W | watt
|
108
|
+
F | farad
|
109
|
+
Hz | hertz
|
110
|
+
C | coulomb
|
111
|
+
S ℧ | siemens
|
112
|
+
H | henry
|
113
|
+
|
114
|
+
Units can be combined with the following prefixes:
|
115
|
+
|
116
|
+
Symbol | Name
|
117
|
+
:-----: | -----
|
118
|
+
k | kilo
|
119
|
+
M | mega
|
120
|
+
G | giga
|
121
|
+
T | tera
|
122
|
+
m | milli
|
123
|
+
μ u | micro
|
124
|
+
n | nano
|
125
|
+
p | pico
|
126
|
+
|
127
|
+
There is also the following abbreviations:
|
128
|
+
|
129
|
+
Symbol | Name
|
130
|
+
:-----: | -----
|
131
|
+
u μ | micro farad
|
132
|
+
n | nano farad
|
133
|
+
p | pico farad
|
134
|
+
k K | kilo ohm
|
114
135
|
|
115
136
|
### What is missing?
|
116
137
|
|
@@ -124,10 +145,10 @@ next couple of days/weeks:
|
|
124
145
|
- [x] More builtin functions (sin, cos, tan)
|
125
146
|
- [x] Exponent
|
126
147
|
- [x] Readline lib in the REPL for a better user experience
|
127
|
-
- [
|
128
|
-
- [
|
148
|
+
- [x] All units and prefix used in electronic
|
149
|
+
- [x] `*` for the multiplication if one want to
|
150
|
+
- [x] √ for an alternative to square root
|
129
151
|
- [ ] Shortcuts for function's names (ie sq and sqr for sqrt)
|
130
|
-
- [ ] All units and prefix used in electronic
|
131
152
|
|
132
153
|
## What's next?
|
133
154
|
|
data/documentation/precedence.md
CHANGED
data/lib/electr.rb
CHANGED
@@ -13,11 +13,12 @@ module Electr
|
|
13
13
|
|
14
14
|
UNARY_MINUS_INTERNAL_SYMBOL = '€'
|
15
15
|
|
16
|
-
ONE_CHAR_OPERATORS = %w( + - / ^ )
|
16
|
+
ONE_CHAR_OPERATORS = %w( + - * / ^ )
|
17
17
|
|
18
18
|
# f - function
|
19
19
|
SYMBOL_TABLE = {
|
20
20
|
'sqrt' => 'f',
|
21
|
+
'√' => 'f',
|
21
22
|
'sin' => 'f',
|
22
23
|
'cos' => 'f',
|
23
24
|
'tan' => 'f',
|
@@ -35,4 +36,14 @@ module Electr
|
|
35
36
|
'+' => {assoc: 'L', val: 1},
|
36
37
|
}
|
37
38
|
|
39
|
+
UNITS = %w( A Hz W C V F R Ω S ℧ H )
|
40
|
+
|
41
|
+
PREFIXES = %w( k M G T m μ u n p )
|
42
|
+
|
43
|
+
# u μ - micro farad
|
44
|
+
# n - nano farad
|
45
|
+
# p - pico farad
|
46
|
+
# k K - kilo ohm
|
47
|
+
ABBREVIATIONS = %w( u μ n p k K )
|
48
|
+
|
38
49
|
end
|
data/lib/electr/option.rb
CHANGED
data/lib/electr/parser.rb
CHANGED
@@ -19,7 +19,7 @@ module Electr
|
|
19
19
|
def self.numeric(value) ; new(:numeric, value) ; end
|
20
20
|
def self.operator(value) ; new(:operator, value) ; end
|
21
21
|
def self.constant(value) ; new(:constant, value) ; end
|
22
|
-
def self.value(value) ; new(:value, value)
|
22
|
+
def self.value(value) ; new(:value, Value.assert(value)) ; end
|
23
23
|
def self.name(value) ; new(:name, value) ; end
|
24
24
|
def self.fname(value) ; new(:fname, value) ; end
|
25
25
|
def self.fcall(value) ; new(:fcall, value) ; end
|
data/lib/electr/parser/token.rb
CHANGED
@@ -94,13 +94,16 @@ module Electr
|
|
94
94
|
add_look_ahead if @look_ahead == '-'
|
95
95
|
add_look_ahead while @look_ahead =~ /[0-9._,]/
|
96
96
|
if @token[-1] != '.'
|
97
|
-
add_look_ahead while @look_ahead =~ /[
|
97
|
+
add_look_ahead while @look_ahead =~ /[A-Za-zΩ℧μ]/
|
98
98
|
end
|
99
99
|
@token
|
100
100
|
end
|
101
101
|
|
102
102
|
def get_word
|
103
|
-
add_look_ahead while @look_ahead =~
|
103
|
+
add_look_ahead while @look_ahead =~ /[\w√]/
|
104
|
+
# At this step, an empty token signify that we have reached an
|
105
|
+
# illegal word.
|
106
|
+
raise(SyntaxError, @codeline) if @token.empty?
|
104
107
|
@token
|
105
108
|
end
|
106
109
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Electr
|
2
|
+
|
3
|
+
class LexicalUnit::Value
|
4
|
+
|
5
|
+
def self.assert(value)
|
6
|
+
new(value).assert
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(value)
|
10
|
+
@value = value
|
11
|
+
@unit = nil
|
12
|
+
@prefix = nil
|
13
|
+
@abbreviation = false
|
14
|
+
find_unit_attributes
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert
|
18
|
+
if good_unit?
|
19
|
+
@value
|
20
|
+
else
|
21
|
+
raise(SyntaxError, "Unknow unit: #@unit in #@value")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def find_unit_attributes
|
28
|
+
find_unit
|
29
|
+
maybe_split_unit
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_unit
|
33
|
+
index = 0
|
34
|
+
index += 1 while @value[index] =~ /[0-9._,-]/
|
35
|
+
@unit = @value[index..-1]
|
36
|
+
end
|
37
|
+
|
38
|
+
def maybe_split_unit
|
39
|
+
if abbreviation?
|
40
|
+
@abbreviation = true
|
41
|
+
elsif prefix?
|
42
|
+
fill_prefix_and_unit
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def abbreviation?
|
47
|
+
@unit.size == 1 && ABBREVIATIONS.include?(@unit)
|
48
|
+
end
|
49
|
+
|
50
|
+
def prefix?
|
51
|
+
PREFIXES.include?(@unit[0])
|
52
|
+
end
|
53
|
+
|
54
|
+
def fill_prefix_and_unit
|
55
|
+
@prefix = @unit[0]
|
56
|
+
@unit = @unit[1..-1]
|
57
|
+
end
|
58
|
+
|
59
|
+
def good_unit?
|
60
|
+
@abbreviation || UNITS.include?(@unit)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/electr/repl/repl.rb
CHANGED
@@ -3,7 +3,7 @@ module Electr
|
|
3
3
|
# The Read Eval Print Loop starting point.
|
4
4
|
class Repl
|
5
5
|
|
6
|
-
BANNER = "\nElectr version #{
|
6
|
+
BANNER = "\nElectr version #{VERSION} (codename «#{CODENAME}»)\n" +
|
7
7
|
"A tiny language for electronic formulas\n\n" +
|
8
8
|
"Hit Ctrl+C to quit Electr\n\n"
|
9
9
|
|
data/lib/electr/version.rb
CHANGED
data/spec/parser/lexer_spec.rb
CHANGED
@@ -29,4 +29,28 @@ describe Lexer do
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
describe "value" do
|
33
|
+
|
34
|
+
it "rejects unknown units" do
|
35
|
+
expect { Lexer.lexify("1P") }.to raise_error(Electr::SyntaxError)
|
36
|
+
expect { Lexer.lexify("1Q") }.to raise_error(Electr::SyntaxError)
|
37
|
+
expect { Lexer.lexify("1X") }.to raise_error(Electr::SyntaxError)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "rejects unknown prefixes" do
|
41
|
+
expect { Lexer.lexify("1bA") }.to raise_error(Electr::SyntaxError)
|
42
|
+
expect { Lexer.lexify("1wW") }.to raise_error(Electr::SyntaxError)
|
43
|
+
expect { Lexer.lexify("1jHz") }.to raise_error(Electr::SyntaxError)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "accepts known units" do
|
47
|
+
expect { Lexer.lexify("1A") }.not_to raise_error
|
48
|
+
end
|
49
|
+
|
50
|
+
it "accepts known prefixes" do
|
51
|
+
expect { Lexer.lexify("1mA") }.not_to raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
32
56
|
end
|
@@ -52,6 +52,13 @@ describe Tokenizer do
|
|
52
52
|
expect(tkr.next_token).to eq "300"
|
53
53
|
end
|
54
54
|
|
55
|
+
specify "2 * 3" do
|
56
|
+
tkr = Tokenizer.new("2 * 3")
|
57
|
+
expect(tkr.next_token).to eq "2"
|
58
|
+
expect(tkr.next_token).to eq "*"
|
59
|
+
expect(tkr.next_token).to eq "3"
|
60
|
+
end
|
61
|
+
|
55
62
|
specify "2 0.6" do
|
56
63
|
tkr = Tokenizer.new("2 0.6")
|
57
64
|
expect(tkr.next_token).to eq "2"
|
@@ -125,6 +132,11 @@ describe Tokenizer do
|
|
125
132
|
expect(tkr.next_token).to eq "sqrt"
|
126
133
|
end
|
127
134
|
|
135
|
+
specify "√(49)" do
|
136
|
+
tkr = Tokenizer.new("√(49)")
|
137
|
+
expect(tkr.next_token).to eq "√"
|
138
|
+
end
|
139
|
+
|
128
140
|
specify "11K 22k 33kΩ" do
|
129
141
|
tkr = Tokenizer.new("11K 22k 33kΩ")
|
130
142
|
expect(tkr.next_token).to eq "11K"
|
@@ -195,4 +207,28 @@ describe Tokenizer do
|
|
195
207
|
expect(tkr.next_token).to eq "2"
|
196
208
|
end
|
197
209
|
|
210
|
+
it 'tokenize units and prefixes' do
|
211
|
+
units = %w( A Hz W C V F R Ω S ℧ H )
|
212
|
+
prefixes = %w( k M G T m μ u n p )
|
213
|
+
|
214
|
+
units.each do |unit|
|
215
|
+
tkr = Tokenizer.new("1#{unit}")
|
216
|
+
expect(tkr.next_token).to eq "1" + unit
|
217
|
+
end
|
218
|
+
|
219
|
+
prefixes.each do |prefix|
|
220
|
+
units.each do |unit|
|
221
|
+
tkr = Tokenizer.new("1#{prefix}#{unit}")
|
222
|
+
expect(tkr.next_token).to eq "1" + prefix + unit
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'raises on illegal token' do
|
228
|
+
tkr = Tokenizer.new("@")
|
229
|
+
expect {
|
230
|
+
tkr.next_token
|
231
|
+
}.to raise_error(Electr::SyntaxError)
|
232
|
+
end
|
233
|
+
|
198
234
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Electr
|
4
|
+
|
5
|
+
describe LexicalUnit::Value do
|
6
|
+
|
7
|
+
describe "assert" do
|
8
|
+
|
9
|
+
it "rejects unknown units" do
|
10
|
+
unknown = %w( 1P 1Q 1X )
|
11
|
+
unknown.each do |unit|
|
12
|
+
expect {
|
13
|
+
LexicalUnit::Value.assert(unit)
|
14
|
+
}.to raise_error(Electr::SyntaxError)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "asserts valid units" do
|
19
|
+
known = %w( 1V 1C 1S )
|
20
|
+
known.each do |unit|
|
21
|
+
expect { LexicalUnit::Value.assert(unit) }.not_to raise_error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "rejects unknown prefixes" do
|
26
|
+
unknown = %w( 1xV 1bV 1wW )
|
27
|
+
unknown.each do |unit|
|
28
|
+
expect {
|
29
|
+
LexicalUnit::Value.assert(unit)
|
30
|
+
}.to raise_error(Electr::SyntaxError)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "accepts valid prefixes" do
|
35
|
+
known = %w( 1mV 1μF 1nF )
|
36
|
+
known.each do |unit|
|
37
|
+
expect { LexicalUnit::Value.assert(unit) }.not_to raise_error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "accepts unit abbreviations" do
|
42
|
+
abbreviations = %w( 1u 1μ 1n 1p 1k 1K )
|
43
|
+
abbreviations.each do |unit|
|
44
|
+
expect { LexicalUnit::Value.assert(unit) }.not_to raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/spec/repl/evaluator_spec.rb
CHANGED
@@ -34,6 +34,8 @@ describe Evaluator do
|
|
34
34
|
{code: "sin(pi / 2) + 1", result: 2},
|
35
35
|
{code: "cos(0) - 1", result: 0},
|
36
36
|
{code: "tan(0) - 1", result: -1},
|
37
|
+
{code: "10 ^ 2", result: 100},
|
38
|
+
{code: "√(49)", result: 7},
|
37
39
|
]
|
38
40
|
|
39
41
|
specify "#evaluate_pn" do
|
@@ -48,12 +50,12 @@ describe Evaluator do
|
|
48
50
|
end
|
49
51
|
|
50
52
|
specify do
|
51
|
-
pns = Compiler.compile_to_pn("
|
53
|
+
pns = Compiler.compile_to_pn("2 * 3")
|
52
54
|
|
53
55
|
evaluator = Evaluator.new
|
54
56
|
result = evaluator.evaluate_pn(pns)
|
55
57
|
|
56
|
-
expect(result).to eq
|
58
|
+
expect(result).to eq 6
|
57
59
|
end
|
58
60
|
|
59
61
|
|
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.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lkdjiin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- lib/electr/parser/syntaxer.rb
|
114
114
|
- lib/electr/parser/token.rb
|
115
115
|
- lib/electr/parser/tokenizer.rb
|
116
|
+
- lib/electr/parser/value.rb
|
116
117
|
- lib/electr/repl.rb
|
117
118
|
- lib/electr/repl/ast_printer.rb
|
118
119
|
- lib/electr/repl/ast_reader.rb
|
@@ -132,6 +133,7 @@ files:
|
|
132
133
|
- spec/parser/pn_spec.rb
|
133
134
|
- spec/parser/sya_spec.rb
|
134
135
|
- spec/parser/tokenizer_spec.rb
|
136
|
+
- spec/parser/value_spec.rb
|
135
137
|
- spec/repl/ast_printer_spec.rb
|
136
138
|
- spec/repl/ast_reader_spec.rb
|
137
139
|
- spec/repl/evaluator_spec.rb
|
@@ -173,6 +175,7 @@ test_files:
|
|
173
175
|
- spec/parser/pn_spec.rb
|
174
176
|
- spec/parser/sya_spec.rb
|
175
177
|
- spec/parser/tokenizer_spec.rb
|
178
|
+
- spec/parser/value_spec.rb
|
176
179
|
- spec/repl/ast_printer_spec.rb
|
177
180
|
- spec/repl/ast_reader_spec.rb
|
178
181
|
- spec/repl/evaluator_spec.rb
|