qlang 0.0.14 → 0.0.27

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