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 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