electr 0.0.2

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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +196 -0
  9. data/Rakefile +7 -0
  10. data/bin/electr +27 -0
  11. data/electr.gemspec +25 -0
  12. data/lib/electr.rb +20 -0
  13. data/lib/electr/ast.rb +9 -0
  14. data/lib/electr/ast/ast.rb +62 -0
  15. data/lib/electr/ast/constant_ast.rb +14 -0
  16. data/lib/electr/ast/func_args_ast.rb +11 -0
  17. data/lib/electr/ast/func_ast.rb +12 -0
  18. data/lib/electr/ast/func_name_ast.rb +14 -0
  19. data/lib/electr/ast/numeric_ast.rb +13 -0
  20. data/lib/electr/ast/operator_ast.rb +13 -0
  21. data/lib/electr/ast/root_ast.rb +11 -0
  22. data/lib/electr/ast/value_ast.rb +12 -0
  23. data/lib/electr/compiler.rb +24 -0
  24. data/lib/electr/evaluator.rb +64 -0
  25. data/lib/electr/exceptions.rb +6 -0
  26. data/lib/electr/option.rb +70 -0
  27. data/lib/electr/parser.rb +5 -0
  28. data/lib/electr/parser/lexer.rb +50 -0
  29. data/lib/electr/parser/lexical_unit.rb +67 -0
  30. data/lib/electr/parser/rules/base_rule.rb +60 -0
  31. data/lib/electr/parser/rules/expression_rule.rb +79 -0
  32. data/lib/electr/parser/rules/root_rule.rb +21 -0
  33. data/lib/electr/parser/sya.rb +105 -0
  34. data/lib/electr/parser/syntaxer.rb +21 -0
  35. data/lib/electr/parser/tokenizer.rb +79 -0
  36. data/lib/electr/repl.rb +56 -0
  37. data/lib/electr/rules.rb +3 -0
  38. data/lib/electr/version.rb +3 -0
  39. data/spec/compiler_spec.rb +42 -0
  40. data/spec/electr_spec.rb +7 -0
  41. data/spec/evaluator_spec.rb +47 -0
  42. data/spec/lexer_spec.rb +29 -0
  43. data/spec/spec_helper.rb +8 -0
  44. data/spec/sya_spec.rb +153 -0
  45. data/spec/tokenizer_spec.rb +102 -0
  46. metadata +138 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 129c7c8560ec169ade1a934c574de8a045e3dbc0
4
+ data.tar.gz: c04ece5fd979bad30c69e5d67b64899b841ac72e
5
+ SHA512:
6
+ metadata.gz: faee90b0d4a72a8bf8c74c9530c697062e7edde33c6c96b0135d56aa93bda5573e1d78647279b7104622300bab369900f1ffd5d2d2be0b30915af20bc5430b6e
7
+ data.tar.gz: c04497b5911bb940656a495eaab0232be5394b456baf27c4f1a209a3aa2e86f27630e986b59b2499ba3c417a0bf557305c1f04fbe698a1795f6dc3a6e23fd23f
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ TODO
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --order=random
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
@@ -0,0 +1,17 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+ This project adheres to [Semantic Versioning](http://semver.org/).
4
+
5
+ ## [Unreleased] - unreleased
6
+
7
+ ## [0.0.2] - 2015-09-04
8
+ ### Added
9
+ - Basic Read-Eval-Print-Loop as a proof of concept. It recognizes some
10
+ units but not all
11
+ - Options -v (version), -h (help), --ast (display the AST instead of the
12
+ result) and -e (compute this expression and quit, do not run
13
+ interactively)
14
+ - Grammar of Electr (in `grammar.md`)
15
+ - Beginning of documentation for developers
16
+ - Precedence table
17
+ - This change log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in electr.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 lkdjiin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,196 @@
1
+ Electr
2
+ ======
3
+
4
+ Interactive language for electronic formulas.
5
+
6
+ ## Rationale
7
+
8
+ - I have not found an open source language or calculator at the command line,
9
+ specialized in electronic formulas
10
+ - I'm always confused with milli, micro, pico, nano, etc
11
+ - I prefer to type 100k rather than 100000, or 100M rather than 100000000
12
+ - If, for any reason, I want to write 100000000, then I should be able to write
13
+ 100_000_000 or 100,000,000
14
+
15
+ I don't want a big monster but a tiny specialized language.
16
+
17
+ ## What do you think?
18
+
19
+ I started to write this tiny language. First, a quick prototype in Ruby, as a
20
+ proof of concept. And then, maybe, a more portable version in C.
21
+
22
+ Tell me what you think on [twitter](https://twitter.com/lkdjiin) or better,
23
+ open an issue here on Github. In any cases feel free to start a discussion.
24
+
25
+ The current version is an early one:
26
+
27
+ 1. Don't expect too much
28
+ 2. Expect a lot of bugs
29
+ 3. Please be kind enough to report any bugs here in Github
30
+
31
+ ## Installation
32
+
33
+ Install it with:
34
+
35
+ $ gem install electr
36
+
37
+ ## Examples of what Electr can do right now
38
+
39
+ ### Start Electr
40
+
41
+ Just type `electr`:
42
+
43
+ $ electr
44
+
45
+ And you'll see the prompt waiting for you:
46
+
47
+ E>
48
+
49
+ To compute an expression without entering the interactive mode, use the `-e`
50
+ switch:
51
+
52
+ $ electr -e "3V / 25mA"
53
+ 120
54
+
55
+ To display the AST instead of doing the computation, use the `--ast` switch
56
+ (*this is intended only for the developers*):
57
+
58
+ $ electr --ast -e "3V / 25mA"
59
+ ast
60
+ root
61
+ operator (/)
62
+ value ::= 3V
63
+ value ::= 25mA
64
+
65
+ ### Resistors in serie
66
+
67
+ Start simple to illustrate the addition. We have a 10,000 Ohm resistor (10k) and
68
+ a 200 Ohm resistor (200R):
69
+
70
+ E> 10k + 200R
71
+ 10200
72
+
73
+ *Should it be `K`, `k`, `kΩ` or the three is still open to debate.*
74
+
75
+ ### Ohm's law
76
+
77
+ Divide Volts (V) by milliamps (mA) to get some Ohms:
78
+
79
+ E> 3V / 25mA
80
+ 120
81
+
82
+ There is no symbol for the multiplication. Simply put values side by side:
83
+
84
+ E> 1mA 3k
85
+ 3
86
+
87
+ ### Frequency of an oscillator
88
+
89
+ A little bit more complex is the computation of a frequency for an oscillator.
90
+ We've got two constants (`2` and `pi`), a value in micro Farad (`0.5uF`) and
91
+ a square root (`sqrt`) of the product of two resistors (`11k 22k`). The result
92
+ is in Hertz.
93
+
94
+ E> 1 / (2 pi 0.5uF sqrt(11k 22k))
95
+ 20.4617344581
96
+
97
+ ### Units
98
+
99
+ Currently Electr knows the following units:
100
+
101
+ Prefix and/or Symbol | Name
102
+ :-------------------: | -----
103
+ k K kΩ | kilo ohm
104
+ Ω R | ohm
105
+ A | ampere
106
+ V | volt
107
+ W | watt
108
+ mA | milli ampere
109
+ mV | milli volt
110
+ mW | milli watt
111
+ μ u μF uF | micro farad
112
+ p pF | pico farad
113
+
114
+ ### What is missing?
115
+
116
+ Electr is at a very early stage and it miss a lot of (basic) things!
117
+ You can expect that the following features will be implemented in the
118
+ next couple of days/weeks:
119
+
120
+ [ ] Negative numbers
121
+ [ ] `*` for the multiplication if one want to
122
+ [ ] √ for an alternative to square root
123
+ [ ] Floating point number without a leading zero (ie `.678`)
124
+ [ ] More buitin functions (sin, cos, tan, etc)
125
+ [ ] Exponent
126
+ [ ] Shortcuts for function's names (ie sq and sqr for sqrt)
127
+ [ ] Readline lib in the REPL for a better user experience
128
+ [ ] 10_000 or 10,000 will be the same as 10000
129
+ [ ] All units and prefix used in electronic
130
+
131
+ ## What's next?
132
+
133
+ Maybe Electr could infer the resulting unit:
134
+
135
+ E> 10k + 200R
136
+ 10.2kΩ
137
+ E> 3V / 25mA
138
+ 120Ω
139
+ E> 3V / 1mA
140
+ 3kΩ
141
+
142
+ One are less prone to typing errors (less parenthesis) if one enter a complex
143
+ expression on two lines:
144
+
145
+ E> 1 /
146
+ E> 2 pi 0.5uF sq(11K 22K)
147
+ 20.46Hz
148
+
149
+ ### Beyond the calculator
150
+
151
+ Electr could be more **interactive**. In the following session we've got a
152
+ resistor R1 and two capacitors C1 and C2. Once the formula is entered, Electr
153
+ ask us for the components values, then gives us the result.
154
+
155
+ E> 1/
156
+ E> 2 pi R1 sq(C1 C2)
157
+ R1=?> 33K
158
+ C1=?> 1000pF
159
+ C2=?> 470pF
160
+ 7.04kHz
161
+
162
+ Or acts like a tiny programming language.
163
+
164
+ E> R1 = 33k
165
+ E> C1 = 1000pF
166
+ E> C2 = 470pF
167
+ E> 1 / (2 pi R1 sq(C1 C2))
168
+ 7.04kHz
169
+
170
+ Why not having custom functions?
171
+
172
+ E> func = { 1 / (2 pi R1 sq(C1 C2)) }
173
+ E> func(R1=33k, C1=1000pF, C2=470pF)
174
+ 7.04kHz
175
+
176
+ *The above syntax is just one possibility amongst a lot of others.*
177
+
178
+ ## Contributing
179
+
180
+ 1. Fork it ( https://github.com/[my-github-username]/electr/fork )
181
+ 2. **PLEASE Create your feature branch** (`git checkout -b my-new-feature`)
182
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
183
+ 4. Push to the branch (`git push origin my-new-feature`)
184
+ 5. Create a new Pull Request
185
+
186
+ ## Alternatives
187
+
188
+ Some people point me to two existing softwares:
189
+
190
+ - [Frink](https://futureboy.us/frinkdocs/)
191
+ - [GNU Units](https://en.wikipedia.org/wiki/GNU_Units)
192
+
193
+ Frink is closed source, so it doesn't meet my requirements. GNU Units is
194
+ awesome and close to what I want but it's so huge and not at all specialized!
195
+ I want to deal with ohms, farads, volts, etc and not with kilograms nor with
196
+ furlongs ;)
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'electr'
4
+
5
+ opt = Electr::Option.new
6
+
7
+ if opt[:expression]
8
+ if opt[:ast]
9
+ compiler = Electr::Compiler.new
10
+ ast = compiler.compile_to_ast(opt[:expression])
11
+ ast.display
12
+ else
13
+ # FIXME Should be under lib/ to be tested and there is a lot of
14
+ # common code with Repl.
15
+ compiler = Electr::Compiler.new
16
+ temp = compiler.compile_to_pn(opt[:expression])
17
+ evaluator = Electr::Evaluator.new
18
+ temp = evaluator.evaluate_pn(temp)
19
+ if temp == temp.truncate
20
+ puts temp.truncate
21
+ else
22
+ puts temp.round(10)
23
+ end
24
+ end
25
+ else
26
+ Electr::Repl.new(opt).run
27
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'electr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "electr"
8
+ spec.version = Electr::VERSION
9
+ spec.authors = ["lkdjiin"]
10
+ spec.email = ["xavier.nayrac@gmail.com"]
11
+ spec.summary = %q{Interactive language for electronic formulas}
12
+ spec.homepage = "https://github.com/lkdjiin/electr"
13
+ spec.license = "MIT"
14
+
15
+ spec.required_ruby_version = ">= 2.2"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec"
25
+ end
@@ -0,0 +1,20 @@
1
+ require "optparse"
2
+
3
+ require "electr/version"
4
+ require "electr/exceptions"
5
+ require "electr/parser"
6
+ require "electr/compiler"
7
+ require "electr/ast"
8
+ require "electr/rules"
9
+ require "electr/evaluator"
10
+ require "electr/repl"
11
+ require "electr/option"
12
+
13
+ module Electr
14
+
15
+ # f - function
16
+ SYMBOL_TABLE = {
17
+ 'sqrt' => 'f',
18
+ }
19
+
20
+ end
@@ -0,0 +1,9 @@
1
+ require "electr/ast/ast"
2
+ require "electr/ast/root_ast"
3
+ require "electr/ast/numeric_ast"
4
+ require "electr/ast/constant_ast"
5
+ require "electr/ast/value_ast"
6
+ require "electr/ast/operator_ast"
7
+ require "electr/ast/func_ast"
8
+ require "electr/ast/func_name_ast"
9
+ require "electr/ast/func_args_ast"
@@ -0,0 +1,62 @@
1
+ module Electr
2
+
3
+ class AST
4
+
5
+ def initialize(name)
6
+ if name
7
+ @name = name
8
+ else
9
+ @name = self.class.name.split('::').last
10
+ end
11
+ @children = []
12
+ @value = nil
13
+ end
14
+
15
+ # Public: Add a child node to the end of the children's list.
16
+ #
17
+ # child - An AST node to add to the list of children.
18
+ #
19
+ # Returns self.
20
+ def add_child child
21
+ @children << child
22
+ self
23
+ end
24
+
25
+ # Public: Returns True if this node is a leaf.
26
+ def leaf?
27
+ @children.empty?
28
+ end
29
+
30
+ def size
31
+ @children.size
32
+ end
33
+
34
+ def display(indent = 0)
35
+ print " " * indent + @name
36
+ if leaf?
37
+ print " ::= #@value"
38
+ else
39
+ print " (#@value)" if @value
40
+ end
41
+ puts
42
+ @children.each {|child| child.display(indent + 2) }
43
+ end
44
+
45
+ def to_pn
46
+ [* Pn.new(@value, @name)] + @children.map {|child| child.to_pn }.flatten
47
+ end
48
+
49
+ end
50
+
51
+ # TODO Pn is not a good name!
52
+ class Pn
53
+
54
+ def initialize(value, name)
55
+ @value = value
56
+ @name = name
57
+ end
58
+
59
+ attr_reader :value, :name
60
+ end
61
+
62
+ end
@@ -0,0 +1,14 @@
1
+ module Electr
2
+
3
+ class ConstantAST < AST
4
+
5
+ def initialize(value)
6
+ super("constant")
7
+ @value = value
8
+ end
9
+
10
+ end
11
+ end
12
+
13
+
14
+