electr 0.0.4 → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ccc906f3bbacaccdd300849c16843c4088b34b6f
4
- data.tar.gz: 6e23419eb9b1435832b10a5f2179930b6e06ca0a
3
+ metadata.gz: 86d47b60ef5f815792290a73257593f50f6819a1
4
+ data.tar.gz: 638a91fb8edea30cf2c782a972c21591efea09f8
5
5
  SHA512:
6
- metadata.gz: 96d87d01a204d8437fc511155240ba7f4cf2fc775c2ab16ff6f293cecadbd5805eb37ab97caa5c9e801cade75af14e981f7d2ebd85c3e63eac5723d59259ab0b
7
- data.tar.gz: c884b9a67e9b481abc08541983ff8ca272ab2a54003e961755596375f4ceba4a6814ac46acd3874aa98802775d9649ab3513957b7201a92589973b76c009b6b0
6
+ metadata.gz: abdf7b5b3f6282134294825cfeeb277d5d2116573f90aa50e1fb4e836ca9b9d99dcee00fccee571225631f83a3e86e856f70c9a091151edcd304355c8b391354
7
+ data.tar.gz: 745e6f0654ab7fea487954ebd0f7443ac18471f89a084f7dca7860c2d332c6276b8d794899c96f951fe9b5b3f0fc3ebdedb077d45c681d43b044cd90ff2c07e8
@@ -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
- Currently Electr knows the following units:
101
-
102
- Prefix and/or Symbol | Name
103
- :-------------------: | -----
104
- k K kΩ | kilo ohm
105
- Ω R | ohm
106
- A | ampere
107
- V | volt
108
- W | watt
109
- mA | milli ampere
110
- mV | milli volt
111
- mW | milli watt
112
- μ u μF uF | micro farad
113
- p pF | pico farad
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
- - [ ] `*` for the multiplication if one want to
128
- - [ ] for an alternative to square root
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
 
@@ -4,5 +4,7 @@ Precedence Table
4
4
  Operator | Description | Associativity
5
5
  :-------: | ------------- | --------------
6
6
  () | Function call | Left
7
+ ^ | Exponent | Left
8
+ - | Unary minus | Right
7
9
  * / | Multiplication and division | Left
8
10
  + - | Addition and substraction | Left
@@ -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
@@ -61,7 +61,7 @@ module Electr
61
61
  private
62
62
 
63
63
  def print_version
64
- puts "Electr version #{VERSION}"
64
+ puts "Electr version #{VERSION} (codename «#{CODENAME}»)"
65
65
  exit
66
66
  end
67
67
 
@@ -2,6 +2,7 @@ require "electr/parser/tokenizer"
2
2
  require "electr/parser/token"
3
3
  require "electr/parser/lexer"
4
4
  require "electr/parser/lexical_unit"
5
+ require "electr/parser/value"
5
6
  require "electr/parser/rules"
6
7
  require "electr/parser/syntaxer"
7
8
  require "electr/parser/sya"
@@ -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) ; end
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
@@ -17,7 +17,7 @@ module Electr
17
17
 
18
18
  def value?
19
19
  # The unit part is redondant with Tokenizer.
20
- self =~ /[0-9.][kKRuFpΩμAmWV]{1,}\Z/
20
+ self =~ /[0-9.][A-Za-zΩ℧μ]{1,}\Z/
21
21
  end
22
22
 
23
23
  end
@@ -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 =~ /[kKRuFpΩμAmWV]/
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 =~ /\w/
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
@@ -4,7 +4,7 @@ module Electr
4
4
 
5
5
  def self.eval(function_name, stack)
6
6
  case function_name
7
- when "sqrt"
7
+ when "sqrt", "√"
8
8
  a = stack.pop
9
9
  stack.push(Math::sqrt(a))
10
10
  when "sin"
@@ -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 #{Electr::VERSION}\n" +
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
 
@@ -1,3 +1,4 @@
1
1
  module Electr
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
+ CODENAME = "Units"
3
4
  end
@@ -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
@@ -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("10 ^ 2")
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 100
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
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-09 00:00:00.000000000 Z
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