electr 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
+