qlang 0.0.14 → 0.0.27

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,16 @@
1
+ require 'pry'
1
2
  module Qlang
2
3
  module Lexer
3
4
  class WrapLexer < Base
4
- rule(/\w\(\w( ?, ?\w)*\) ?= ?[^\r\n]+/) { :FUNC }
5
+ rule(%r@#{FUNCCV}#{ANYSP}=#{ANYSP}#{NONL}+@) { :def_func }
6
+ rule(%r@#{FUNCCN}@) { :eval_func }
7
+ rule(/S#{ANYSP}#{LPRN}#{ANYSTR}#{RPRN}\[#{ANYSTR}\]/) { :integral }
8
+ rule(/d\/d#{VAR} .*/) { :differential }
9
+ rule(%r@#{LPRN}#{NUMS_BY_SP}#{RPRN}@) { :vector }
10
+ rule(%r@#{LPRN}#{NUMS_BY_SP_BY_SCLN}#{RPRN}t@) { :tmatrix }
11
+ rule(%r@#{LPRN}#{NUMS_BY_SP_BY_SCLN}#{RPRN}@) { :matrix }
12
+
13
+
5
14
  rule(/\(/) { :LPRN }
6
15
  rule(/\)/) { :RPRN }
7
16
  rule(/\{/) { :LBRC }
data/lib/qlang/parser.rb CHANGED
@@ -8,55 +8,75 @@ require 'qlang/parser/matrix_parser'
8
8
  require 'qlang/parser/vector_parser'
9
9
  require 'qlang/parser/list_parser'
10
10
  require 'qlang/parser/func_parser'
11
+ require 'qlang/parser/integral_parser'
12
+ require 'qlang/parser/formula_parser'
11
13
 
12
14
  module Qlang
13
15
  module Parser
14
16
  def execute(lexed)
15
17
  time = Time.now
16
18
  until lexed.token_str =~ /\A(:NLIN\d|:R\d)+\z/
17
- binding.pry if Time.now > time + 10
19
+ fail "I'm so sorry, something wrong. Please feel free to report this." if Time.now > time + 10
18
20
 
19
21
  case lexed.token_str
22
+ when /(:vector)(\d)/, /(:matrix)(\d)/, /(:tmatrix)(\d)/, /(:integral)(\d)/, /(:def_func)(\d)/
23
+ token_sym = $1.delete(':').to_sym
24
+ token_position = $2.to_i
25
+ token_val = lexed.lexeds[token_position][token_sym]
26
+
27
+ parsed = case token_sym
28
+ when :vector
29
+ VectorParser.execute(token_val)
30
+ when :matrix
31
+ MatrixParser.execute(token_val)
32
+ when :tmatrix
33
+ MatrixParser.execute(token_val, trans: true)
34
+ when :integral
35
+ IntegralParser.execute(token_val)
36
+ when :def_func
37
+ FuncParser.execute(token_val)
38
+ end
39
+ lexed.parsed!(token_position, parsed)
40
+
20
41
  when /:LPRN\d(:CONT\d):RPRN\d/
21
42
  cont_token_with_num = $1
22
43
  cont_lexed = Lexer::ContLexer.new(lexed.get_value(cont_token_with_num))
23
44
 
24
- case cont_lexed.token_str
25
- when /(:NUM\d)+(:SCLN\d|:NLIN\d)(:NUM\d)/
26
- cont = MatrixParser.execute(cont_lexed)
27
- lexed.squash_with_prn(cont_token_with_num, cont)
28
- when /(:NUM\d)+/
29
- cont = VectorParser.execute(cont_lexed)
30
- lexed.squash_with_prn(cont_token_with_num, cont)
31
- end
45
+ cont = "(#{cont_lexed.values.join(' ')})"
46
+ lexed.squash_with_prn(cont_token_with_num, cont)
32
47
 
33
48
  when /:LBRC\d(:CONT\d):RBRC\d/
34
49
  cont_token_with_num = $1
35
50
  cont_lexed = Lexer::ContLexer.new(lexed.get_value(cont_token_with_num))
36
51
 
37
52
  case cont_lexed.token_str
38
- when /(:OTHER\d:CLN\d(:STR\d|:NUM\d|:R\d):CMA)*(:OTHER\d:CLN\d(:STR\d|:NUM\d|:R\d))/
53
+ when /(:SYM\d:CLN\d(:STR\d|:NUM\d|:R\d):CMA)*(:SYM\d:CLN\d(:STR\d|:NUM\d|:R\d))/
39
54
  cont = ListParser.execute(cont_lexed)
40
- lexed.squash_with_prn(cont_token_with_num, cont)
55
+ else
56
+ cont = "{#{cont_lexed.values.join(' ')}}"
41
57
  end
58
+ lexed.squash_with_prn(cont_token_with_num, cont)
42
59
 
43
- when /:FUNC\d/
60
+ when /:eval_func\d/
44
61
  cont_token_with_num = $&
45
- cont_lexed = Lexer::FuncLexer.new(lexed.get_value(cont_token_with_num))
46
-
47
- case cont_lexed.token_str
48
- when /:FDEF\d:EQL\d:OTHER\d/
49
- cont = FuncParser.execute(cont_lexed)
50
- lexed.ch_value(cont_token_with_num, cont)
51
- lexed.ch_token(cont_token_with_num, :R)
52
- end
62
+ cont = lexed.get_value(cont_token_with_num)
63
+ lexed.squash_with_prn(cont_token_with_num, cont)
53
64
 
65
+ when /:differential\d/
66
+ cont_token_with_num = $&
67
+ cont = lexed.get_value(cont_token_with_num)
68
+ cont =~ /(d\/d[a-zA-Z]) (.*)/
69
+ cont = "#{$1}(#{FormulaParser.execute($2)})"
70
+ # FIX: Refactor
71
+ #cont.gsub!(/(d\/d[a-zA-Z]) (.*)/, "\1(\2)")
72
+ lexed.squash_with_prn(cont_token_with_num, cont)
54
73
  when /:CONT\d/
55
74
  lexed.ch_token($&, :R)
56
75
  end
57
76
 
58
77
  lexed.squash_to_cont($1, 2) if lexed.token_str =~ /(:CONT\d|:R\d)(:CONT\d|:R\d)/
59
78
  end
79
+
60
80
  lexed.fix_r_txt!
61
81
  lexed.values.join
62
82
  end
@@ -2,19 +2,6 @@ module Qlang
2
2
  module Parser
3
3
  module Base
4
4
  include ::Qlang::Api
5
- # TODO:
6
- class ::String
7
- def rm(str_or_rgx)
8
- gsub!(str_or_rgx, '')
9
- end
10
-
11
- def rms(*str_or_rgxs)
12
- str_or_rgxs.each do |str_or_rgx|
13
- rm(str_or_rgx)
14
- end
15
- self
16
- end
17
- end
18
5
  end
19
6
  end
20
7
  end
@@ -0,0 +1,36 @@
1
+ module Qlang
2
+ module Parser
3
+ # FIX:
4
+ module FormulaParser
5
+ def execute(lexed)
6
+ ss = StringScanner.new(lexed)
7
+ result = ''
8
+ until ss.eos?
9
+ { EXP: /\^/, BFUNC: /sin|cos|tan|log/, MUL: /(pi|[1-9a-z]){2,}/, SNGL: /(pi|[1-9a-z])/, OTHER: /([^\^1-9a-z]|^pi)+/ }.each do |token , rgx|
10
+ if ss.scan(rgx)
11
+ item = case token
12
+ when :EXP
13
+ $type == :Ruby ? '**' : '^'
14
+ when :MUL
15
+ sss = StringScanner.new(ss[0])
16
+ ary = []
17
+ until sss.eos?
18
+ [/pi/, /[1-9a-z]/].each do |rgx2|
19
+ ary << sss[0] if sss.scan(rgx2)
20
+ end
21
+ end
22
+ ary.join(' * ')
23
+ else
24
+ ss[0]
25
+ end
26
+ result += item
27
+ break
28
+ end
29
+ end
30
+ end
31
+ result
32
+ end
33
+ module_function :execute
34
+ end
35
+ end
36
+ end
@@ -1,14 +1,13 @@
1
+ require 'qlang/lexer/tokens'
1
2
  module Qlang
2
3
  module Parser
3
4
  module FuncParser
4
5
  include Base
5
- def execute(lexed)
6
- lexed.fix_r_txt!
7
- fdef_ary = lexed[0][:FDEF].split('')
8
- func_name = fdef_ary.shift
9
- args = fdef_ary.join.rms('(', ')', ',', ' ').split('')
10
-
11
- FuncApi.execute(func_name, args, lexed[-1][:OTHER])
6
+ include Lexer::Tokens
7
+ def execute(string)
8
+ def_func, formula = string.split(/ *= */)
9
+ def_func =~ %r@(#{FUNCV})#{LPRN}#{ANYSP}(#{VARS_BY_CMA})#{ANYSP}#{RPRN}@
10
+ FuncApi.execute($1, $2.split(' *,'), FormulaParser.execute(formula))
12
11
  end
13
12
  module_function :execute
14
13
  end
@@ -0,0 +1,15 @@
1
+ module Qlang
2
+ module Parser
3
+ module IntegralParser
4
+ include Base
5
+ def execute(string)
6
+ integrated, range = string.scan(/S *\((.+)\)\[(.+)\]/).first
7
+
8
+ integrated.rm!(' ')
9
+
10
+ IntegralApi.execute(FormulaParser.execute(integrated[0..-3]), integrated[-2..-1], range)
11
+ end
12
+ module_function :execute
13
+ end
14
+ end
15
+ end
@@ -2,9 +2,13 @@ module Qlang
2
2
  module Parser
3
3
  module MatrixParser
4
4
  include Base
5
- def execute(lexed)
6
- rows = lexed.split(';')
5
+ def execute(lexed_string, trans: false)
6
+ lexed_string.rms!(')','(', 't')
7
+ rows = lexed_string.split(/ *; */).map(&:split_by_sp)
7
8
  rows.all? { |row| row.count == rows.first.count }
9
+ if trans
10
+ rows = rows.transpose
11
+ end
8
12
  MatrixApi.execute(rows)
9
13
  end
10
14
  module_function :execute
@@ -2,8 +2,10 @@ module Qlang
2
2
  module Parser
3
3
  module VectorParser
4
4
  include Base
5
- def execute(lexed)
6
- VectorApi.execute(lexed.values)
5
+ def execute(lexed_string)
6
+ lexed_string.rms!(/ *\( */, / *\) */)
7
+ elements = lexed_string.split_by_sp
8
+ VectorApi.execute(elements)
7
9
  end
8
10
  module_function :execute
9
11
  end
data/lib/qlang/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qlang
2
- VERSION = "0.0.14"
2
+ VERSION = "0.0.27"
3
3
  end
data/q_lang.gemspec CHANGED
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
+ spec.add_dependency "dydx", '~> 0.1.41421'
22
+
21
23
  spec.add_development_dependency "bundler", "~> 1.6"
22
24
  spec.add_development_dependency "rake"
23
25
  spec.add_development_dependency "rspec"
24
- spec.add_development_dependency "dydx"
25
26
  end
data/spec/iq_spec.rb ADDED
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+
3
+ describe Qlang do
4
+ describe Iq do
5
+ def self.def_test(name, input, output)
6
+ it name + '_def' do
7
+ expect(Iq.execute(input)).to eq(output)
8
+ end
9
+ end
10
+
11
+ def self.cal_test(name, input, output)
12
+ it name + '_cal' do
13
+ expect(Iq.execute(input)).to eq(output)
14
+ reset
15
+ end
16
+ end
17
+
18
+ describe 'General' do
19
+ cal_test('ex1', '2x', '2x')
20
+ cal_test('ex2', 'x + x', '2x')
21
+ cal_test('ex3', 'x * y', 'xy')
22
+ end
23
+
24
+ describe 'Matrix' do
25
+ cal_test('ex1',
26
+ '(1 2 3; 4 5 6)',
27
+ '(1 2 3; 4 5 6)'
28
+ )
29
+
30
+ cal_test('ex2',
31
+ '(1 2 3; 4 5 6) + (1 2 3; 4 5 6)',
32
+ '(2 4 6; 8 10 12)'
33
+ )
34
+
35
+ cal_test('ex3',
36
+ '(1 2 3; 4 5 6) - (2 4 1; 8 3 9)',
37
+ '(-1 -2 2; -4 2 -3)'
38
+ )
39
+
40
+ cal_test('ex4',
41
+ '(1 2; 3 4) * (1 2; 3 4)',
42
+ '(7 10; 15 22)'
43
+ )
44
+
45
+ cal_test('ex5',
46
+ '(1 2; 3 4) ** 2',
47
+ '(7 10; 15 22)'
48
+ )
49
+
50
+ cal_test('ex6',
51
+ '(1 2; 3 4) ** 2',
52
+ '(7 10; 15 22)'
53
+ )
54
+
55
+ cal_test('ex7',
56
+ '(1 2; 3 4) * (1 2)',
57
+ '(5 11)'
58
+ )
59
+
60
+ cal_test('ex8',
61
+ '(1 2 3; 4 5 6)t',
62
+ '(1 4; 2 5; 3 6)'
63
+ )
64
+ end
65
+
66
+ describe 'Vector' do
67
+ it do
68
+ expect(Iq.execute('(1 2 3)')).to eq('(1 2 3)')
69
+ expect(Iq.execute('(1 2 3) + (1 2 3)')).to eq('(2 4 6)')
70
+ expect(Iq.execute('(1 2 3 ) + ( 1 2 3 )')).to eq('(2 4 6)')
71
+ expect(Iq.execute('(1 2 3) - (1 2 3) - (1 2 3)')).to eq('(-1 -2 -3)')
72
+ end
73
+ end
74
+
75
+ describe 'List' do
76
+ it do
77
+ end
78
+ end
79
+
80
+ describe 'Diff' do
81
+ it do
82
+ expect(Iq.execute('d/dx(e ** x)')).to eq('e ^ x')
83
+ expect(Iq.execute('d/dx(x ** 2)')).to eq('2x')
84
+ expect(Iq.execute('d/dx(x * 2)')).to eq('2')
85
+ expect(Iq.execute('d/dx( sin(x) )')).to eq('cos( x )')
86
+ expect(Iq.execute('d/dx(log( x ))')).to eq('1 / x')
87
+ end
88
+ cal_test('ex1', 'd/dx cos(x)', '- sin( x )')
89
+ cal_test('ex2', 'd/dx xx', '2x')
90
+ end
91
+
92
+ describe 'Integral' do
93
+ it do
94
+ expect(Iq.execute('S( log(x)dx )[0..1]')).to eq('-oo')
95
+ expect(Iq.execute('S( sin(x)dx )[0..pi]')).to eq('2.0')
96
+ expect(Iq.execute('S( cos(x)dx )[0..pi]')).to eq('0.0')
97
+ expect(Iq.execute('S( cos(x)dx )[0..pi]')).to eq('0.0')
98
+ end
99
+ cal_test('ex1', 'S(xx dx)[0..1]', '0.33333333')
100
+ cal_test('ex2', 'S(2pi dx)[0..1]', '6.28318531')
101
+ end
102
+
103
+ describe 'Function' do
104
+ def_test('ex1', 'f(x, y) = x + y', 'x + y')
105
+ cal_test('ex1', 'f( 4, 5 )', '9.0')
106
+
107
+ def_test('ex2', 'f( x , y) = xy', 'x * y')
108
+ cal_test('ex2', 'f( 3, 9 )', '27.0')
109
+
110
+ def_test('ex3', 'f(x, y) = xy^2', 'x * ( y ** 2 )')
111
+ cal_test('ex3', 'f( 3, 2 )', '12.0')
112
+
113
+ def_test('ex4', 'f(x, y) = xy^2', 'x * ( y ** 2 )')
114
+ cal_test('ex4', 'df/dx', 'y ^ 2')
115
+
116
+ def_test('ex5', 'g(x) = x ^ 2', 'x ** 2')
117
+ cal_test('ex5', 'g(2)', '4.0')
118
+
119
+ def_test('ex6', 'h(x) = e ^ 2', 'e ** 2')
120
+ cal_test('ex6', 'h(2)', '7.3890560989306495')
121
+
122
+ def_test('ex7', 'h(x) = pix', 'pi * x')
123
+ cal_test('ex7', 'h(3)', '9.42477796076938')
124
+
125
+ def_test('ex8', 'h(x) = pie', 'pi * e')
126
+ cal_test('ex8', 'h(2)', '8.539734222673566')
127
+
128
+ def_test('ex9', 'h(x) = ( 1 / ( 2pi ) ^ ( 1 / 2.0 ) ) * e ^ ( - x ^ 2 / 2 )', '( ( 4503599627370496 / 6369051672525773 ) / ( pi ** 0.5 ) ) * ( e ** ( ( - ( x ** 2 ) ) / 2 ) )')
129
+ cal_test('ex9', 'S( h(x)dx )[-oo..oo]', '1.0')
130
+
131
+ def_test('ex10', 'f(x) = sin(x)', 'sin( x )')
132
+ cal_test('ex10', 'f(pi)', '0.0')
133
+
134
+ def_test('ex11', 'f(x) = cos(x)', 'cos( x )')
135
+ cal_test('ex11', 'f(pi)', '-1.0')
136
+
137
+ def_test('ex11', 'f(x) = log(x)', 'log( x )')
138
+ cal_test('ex11', 'f(e)', '1.0')
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Regular expressions' do
4
+ def self.should_match(num, rgx, str)
5
+ it 'ex' + num.to_s do
6
+ expect(rgx =~ str).to eq(0)
7
+ end
8
+ end
9
+ describe 'function' do
10
+ should_match(1, /[fgh]\(\w( ?, ?\w)*\) ?= ?[^\r\n]+/, 'f(x) = xy')
11
+ end
12
+
13
+ describe 'differentiate' do
14
+ rgx = /d\/d[a-zA-Z] .*/
15
+ should_match(1, rgx, 'd/dx sin(x)')
16
+ should_match(2, rgx, 'd/dz z^2')
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Qlang do
4
+ describe 'Function' do
5
+ context 'into R' do
6
+ it do
7
+ expect(
8
+ Q.to_r.compile('f(x, y) = x + y')
9
+ ).to eq(
10
+ "f <- function(x, y) x + y"
11
+ )
12
+
13
+ expect(
14
+ Q.to_r.compile('g(x) = x ^ 2')
15
+ ).to eq(
16
+ "g <- function(x) x ^ 2"
17
+ )
18
+
19
+ expect(
20
+ Q.to_r.compile('g(x) = x ^ (2 + 2)')
21
+ ).to eq(
22
+ "g <- function(x) x ^ (2 + 2)"
23
+ )
24
+
25
+ expect(
26
+ Q.to_r.compile('h(a, b, c) = a ^ 2 + b ^ 2 + c ^ 2')
27
+ ).to eq(
28
+ "h <- function(a, b, c) a ^ 2 + b ^ 2 + c ^ 2"
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end