qlang 0.0.27182000 → 0.0.27182100

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/README.md +17 -1
  4. data/Rakefile +16 -3
  5. data/bin/qlang +7 -1
  6. data/ext/qlang/QMatrix/q_matrix.c +0 -0
  7. data/ext/qlang/extconf.rb +3 -0
  8. data/ext/qlang/qlang.c +65 -0
  9. data/ext/qlang/qlang.h +6 -0
  10. data/{spec → legacy_rspec}/langs/Haskell/ex1_after.hs +0 -0
  11. data/{spec → legacy_rspec}/langs/Haskell/ex1_before.hs +0 -0
  12. data/{spec → legacy_rspec}/langs/Python/ex1_after.py +0 -0
  13. data/{spec → legacy_rspec}/langs/Python/ex1_before.py +0 -0
  14. data/{spec → legacy_rspec}/langs/R/ex1_after.R +0 -0
  15. data/{spec → legacy_rspec}/langs/R/ex1_before.R +0 -0
  16. data/{spec → legacy_rspec}/objects/list_spec.rb +0 -0
  17. data/{spec → legacy_rspec}/objects/matrix_spec.rb +0 -0
  18. data/{spec → legacy_rspec}/objects/vector_spec.rb +0 -0
  19. data/lib/qlang.rb +21 -18
  20. data/lib/qlang/api/func_api.rb +1 -1
  21. data/lib/qlang/api/integral_api.rb +1 -1
  22. data/lib/qlang/api/list_api.rb +1 -1
  23. data/lib/qlang/api/matrix_api.rb +1 -1
  24. data/lib/qlang/api/vector_api.rb +1 -1
  25. data/lib/qlang/iq.rb +5 -2
  26. data/lib/qlang/lexer.rb +2 -2
  27. data/lib/qlang/lexer/base.rb +31 -14
  28. data/lib/qlang/lexer/formula_lexer.rb +20 -0
  29. data/lib/qlang/lexer/main_lexer.rb +25 -0
  30. data/lib/qlang/lexer/tokens.rb +27 -15
  31. data/lib/qlang/parser.rb +29 -41
  32. data/lib/qlang/parser/formula_parser.rb +25 -25
  33. data/lib/qlang/parser/func_parser.rb +2 -2
  34. data/lib/qlang/parser/integral_parser.rb +2 -2
  35. data/lib/qlang/parser/matrix_parser.rb +3 -3
  36. data/lib/qlang/parser/vector_parser.rb +4 -4
  37. data/lib/qlang/version.rb +1 -1
  38. data/{q_lang.gemspec → qlang.gemspec} +4 -2
  39. data/test/internal/test_tokens.rb +36 -0
  40. data/test/interpreter/base.rb +17 -0
  41. data/test/interpreter/test_differential.rb +44 -0
  42. data/test/interpreter/test_function.rb +45 -0
  43. data/test/interpreter/test_general.rb +13 -0
  44. data/test/interpreter/test_integral.rb +39 -0
  45. data/test/interpreter/test_matrix.rb +71 -0
  46. data/test/interpreter/test_vector.rb +29 -0
  47. data/test/langs/test_r.rb +33 -0
  48. data/test/langs/test_ruby.rb +10 -0
  49. data/{spec/spec_helper.rb → test/minitest_helper.rb} +4 -4
  50. data/test/q_matrix/test_q_matrix.rb +13 -0
  51. data/test/test_qlang.rb +25 -0
  52. metadata +65 -43
  53. data/.rspec +0 -2
  54. data/lib/qlang/lexer/cont_lexer.rb +0 -20
  55. data/lib/qlang/lexer/func_lexer.rb +0 -13
  56. data/lib/qlang/lexer/wrap_lexer.rb +0 -25
  57. data/spec/iq_spec.rb +0 -141
  58. data/spec/lexer/regular_expressions_spec.rb +0 -45
  59. data/spec/objects/function_spec.rb +0 -33
  60. data/spec/objects/integral_spec.rb +0 -21
  61. data/spec/q_lang_spec.rb +0 -47
@@ -6,15 +6,18 @@ module Qlang
6
6
  FLO = /[0-9]+\.[0-9]+/
7
7
  E = /e/
8
8
  PI = /pi/
9
- NUM = /(#{FLO}|#{INT}|#{E}|#{PI})/
9
+ NUM = /(?:#{FLO}|#{INT}|#{E}|#{PI})/
10
10
 
11
11
  # FUNCTION
12
- EMBEDDED_FUNC = /(sin|cos|tan|log)/
12
+ LPRN = /\(/
13
+ RPRN = /\)/
14
+ EMBEDDED_FUNC = /(?:sin|cos|tan|log)/
13
15
  USER_FUNC = /[a-zA-Z]/
14
- FUNCV = /(#{EMBEDDED_FUNC}|#{USER_FUNC})/
16
+ # h(x + y) != h * (x + y)
17
+ FUNCV = /(?:#{EMBEDDED_FUNC}|#{USER_FUNC})(?=#{LPRN})/
15
18
 
16
19
  # VARIABLE
17
- VAR = /([a-d]|[f-z])/
20
+ VAR = /(?:[a-d]|[f-z])/
18
21
  #VAR_MUL2 = /(?!pi)#{VAR}{2}/
19
22
  # #VAR_MUL3 = /(?!#{EMBEDDED_FUNC})#{VAR}{3}/
20
23
  # # FIX:
@@ -30,30 +33,39 @@ module Qlang
30
33
  MUL = /\*/
31
34
  DIV = /\//
32
35
  EXP = /(\*\*|\^)/
33
- OPE = /(#{PLS}|#{SUB}|#{MUL}|#{DIV}|#{EXP})/
36
+ OPE = /(?:#{PLS}|#{SUB}|#{MUL}|#{DIV}|#{EXP})/
34
37
 
35
- VARNUM = /(#{NUM}|#{VAR})/
38
+ VARNUM = /(?:#{NUM}|#{VAR})/
36
39
  ANYSP = ' *'
37
40
  ANYSTR = /.+/
38
41
  NONL = /[^\r\n]/
39
42
 
40
- LPRN = /\(/
41
- RPRN = /\)/
42
- PRN = /(#{LPRN}|#{RPRN})/
43
43
 
44
- LBRC = /\{/
45
- RBRC = /\}/
46
- BRC = /(#{LBRC}|#{RBRC})/
44
+ PRN = /(?:#{LPRN}|#{RPRN})/
45
+
46
+ LBRCS = /\{/
47
+ RBRCS = /\}/
48
+ BRCS = /(?:#{LBRCS}|#{RBRCS})/
49
+
50
+ LBRCT = /\[/
51
+ RBRCT = /\]/
52
+ BRCT = /(?:#{LBRCT}|#{RBRCT})/
47
53
 
48
54
  CLN = /\:/
49
55
  SCLN = /;/
50
56
  CMA = /\,/
57
+ EQL = /\=/
51
58
  SP = / /
59
+ NLIN = /(\r|\n)/
60
+
61
+ ITGRLSYM = 'S'
62
+ # FIXIT
63
+ SCLN_OR_NELN = /(?:#{SCLN}|#{NLIN})/
52
64
 
53
65
  # TODO: what is better
54
66
  class Util
55
67
  def self.string_out(str, partition)
56
- /#{ANYSP}#{str}(#{ANYSP}#{partition}#{ANYSP}#{str})*#{ANYSP}/
68
+ /#{ANYSP}#{str}(?:#{ANYSP}#{partition}#{ANYSP}#{str})*#{ANYSP}/
57
69
  end
58
70
 
59
71
  def self.func_call(args)
@@ -70,9 +82,9 @@ module Qlang
70
82
  FUNCCV = Util.func_call(VARS_BY_CMA)
71
83
  FUNCCVN = Util.func_call(VARNUMS_BY_CMA)
72
84
 
73
- NUMS_BY_SP_BY_SCLN = Util.string_out(NUMS_BY_SP, SCLN)
85
+ NUMS_BY_SP_BY_SCLN_OR_NELN = Util.string_out(NUMS_BY_SP, SCLN_OR_NELN)
74
86
 
75
- FORMULA = /(#{OPE}|#{FUNCV}|#{VAR}|#{NUM}|#{PRN}|#{ANYSP})+/
87
+ FORMULA = /(?:#{OPE}|#{FUNCV}|#{VAR}|#{NUM}|#{PRN}|#{ANYSP})+/
76
88
  end
77
89
  end
78
90
  end
@@ -1,8 +1,5 @@
1
1
  require 'qlang/api'
2
2
 
3
- require 'qlang/lexer/cont_lexer'
4
- require 'qlang/lexer/func_lexer'
5
-
6
3
  require 'qlang/parser/base'
7
4
  require 'qlang/parser/matrix_parser'
8
5
  require 'qlang/parser/vector_parser'
@@ -18,43 +15,42 @@ module Qlang
18
15
  ONEHASH = "#{ANYSP}#{SYM}#{CLN}#{ANYSP}#{VARNUM}#{ANYSP}" # sdf: 234
19
16
  def execute(lexed)
20
17
  time = Time.now
21
- until lexed.token_str =~ /\A(:NLIN\d|:R\d)+\z/
18
+ until lexed.token_str =~ /\A:(NLIN|R)\d+\z/
22
19
  fail "I'm so sorry, something wrong. Please feel free to report this." if Time.now > time + 10
23
20
 
24
21
  case lexed.token_str
25
- when /(:vector)(\d)/, /(:matrix)(\d)/, /(:tmatrix)(\d)/, /(:integral)(\d)/, /(:def_func)(\d)/
26
- token_sym = $1.delete(':').to_sym
27
- token_position = $2.to_i
28
- token_val = lexed.lexeds[token_position][token_sym]
22
+ when /:(vector)(\d+)/, /:(matrix)(\d+)/, /:(tmatrix)(\d+)/, /:(integral)(\d+)/, /:(def_func)(\d+)/, /:(differential)(\d+)/
23
+ token_els = lexed[$2][:els]
29
24
 
30
- parsed = case token_sym
31
- when :vector
32
- VectorParser.execute(token_val)
33
- when :matrix
34
- MatrixParser.execute(token_val)
35
- when :tmatrix
36
- MatrixParser.execute(token_val, trans: true)
37
- when :integral
38
- IntegralParser.execute(token_val)
39
- when :def_func
40
- FuncParser.execute(token_val)
25
+ parsed = case $1
26
+ when 'vector'
27
+ VectorParser.execute(token_els)
28
+ when 'matrix'
29
+ MatrixParser.execute(token_els)
30
+ when 'tmatrix'
31
+ MatrixParser.execute(token_els, trans: true)
32
+ when 'integral'
33
+ IntegralParser.execute(token_els)
34
+ when 'def_func'
35
+ FuncParser.execute(token_els)
36
+ when 'differential'
37
+ del_var, formula = token_els
38
+ "d/d#{del_var}(#{FormulaParser.execute(formula)})"
41
39
  end
42
- lexed.parsed!(parsed, token_position)
40
+ lexed.parsed!(parsed, $2)
43
41
 
44
- when /:LPRN(\d):CONT\d:RPRN(\d)/
45
- tokens_range = $1.to_i..$2.to_i
46
- token_val = lexed.lexeds[tokens_range.to_a[1]][:CONT]
42
+ when /:LPRN(\d+):CONT(\d+):RPRN(\d+)/
43
+ tokens_range = $1.to_i..$3.to_i
44
+ token_val = lexed[$2][:CONT]
47
45
 
48
- cont_lexed = Lexer::ContLexer.new(token_val)
49
- cont = cont_lexed.values.join(' ')
50
- lexed.parsed!(cont.parentheses, tokens_range)
46
+ lexed.parsed!(token_val.parentheses, tokens_range)
51
47
 
52
- when /:LBRC(\d):CONT\d:RBRC(\d)/
53
- tokens_range = $1.to_i..$2.to_i
54
- token_val = lexed.lexeds[tokens_range.to_a[1]][:CONT]
48
+ when /:LBRCS(\d+):CONT(\d+):RBRCS(\d+)/
49
+ tokens_range = $1.to_i..$3.to_i
50
+ token_val = lexed[$2][:CONT]
55
51
 
56
52
  cont = case token_val
57
- when %r@#{ONEHASH}(#{CMA}#{ONEHASH})*@
53
+ when /#{ONEHASH}(#{CMA}#{ONEHASH})*/
58
54
  ListParser.execute(token_val)
59
55
  else
60
56
  token_val
@@ -62,22 +58,14 @@ module Qlang
62
58
 
63
59
  lexed.parsed!(cont, tokens_range)
64
60
 
65
- when /:eval_func(\d)/
61
+ when /:FUNCCN(\d+)/
66
62
  token_val = lexed.get_value($1)
67
63
  lexed.parsed!(token_val.parentheses, $1)
68
64
 
69
- when /:differential(\d)/
70
- token_position = $1.to_i
71
- cont = lexed.get_value(token_position)
72
- cont =~ /(d\/d[a-zA-Z]) (.*)/
73
- cont = "#{$1}(#{FormulaParser.execute($2)})"
74
- # FIX: Refactor
75
- #cont.gsub!(/(d\/d[a-zA-Z]) (.*)/, "\1(\2)")
76
- lexed.parsed!(cont.parentheses, token_position)
77
- when /:CONT(\d)/
65
+ when /:CONT(\d+)/
78
66
  lexed.parsed!(lexed.get_value($1), $1)
79
67
  end
80
- lexed.squash!(($1.to_i)..($1.to_i+1)) if lexed.token_str =~ /(?::CONT|:R)(\d)(?::CONT|:R)(\d)/
68
+ lexed.squash!(($1.to_i)..($1.to_i+1)) if lexed.token_str =~ /:(?:CONT|R)(\d+):(?:CONT|R)(\d+)/
81
69
  end
82
70
 
83
71
  LangEqualizer.execute(
@@ -1,36 +1,36 @@
1
+ require 'qlang/lexer/formula_lexer'
2
+
1
3
  module Qlang
2
4
  module Parser
3
- # FIX:
4
5
  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
- $meta_info.lang == :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]
6
+ include Lexer::Tokens
7
+
8
+ def self.execute(str)
9
+ lexed = Lexer::FormulaLexer.new(str)
10
+ time = Time.now
11
+ loop do
12
+ fail "I'm so sorry, something wrong. Please feel free to report this." if Time.now > time + 10
13
+ case lexed.token_str
14
+ when /:EXP(\d+)/
15
+ new_ope = $meta_info.lang == :ruby ? '**' : '^'
16
+ lexed.parsed!(new_ope, $1)
17
+ when /:MUL(\d+)/
18
+ sss = StringScanner.new(lexed.get_value($1))
19
+ ary = []
20
+ until sss.eos?
21
+ [/pi/, /[1-9a-z]/].each do |rgx2|
22
+ ary << sss[0] if sss.scan(rgx2)
25
23
  end
26
- result += item
27
- break
28
24
  end
25
+ parsed = ary.join(' * ')
26
+
27
+ lexed.parsed!(parsed, $1)
28
+ else
29
+ break
29
30
  end
30
31
  end
31
- result
32
+ lexed.values.join
32
33
  end
33
- module_function :execute
34
34
  end
35
35
  end
36
36
  end
@@ -4,8 +4,8 @@ module Qlang
4
4
  module FuncParser
5
5
  include Base
6
6
  include Lexer::Tokens
7
- def execute(string)
8
- def_func, formula = string.split(/ *= */)
7
+ def execute(els)
8
+ def_func, formula = els[0], els[1]
9
9
  def_func =~ /(#{USER_FUNC})#{LPRN}#{ANYSP}(#{VARS_BY_CMA})#{ANYSP}#{RPRN}/
10
10
  FuncApi.execute($1, $2.split(' *,'), FormulaParser.execute(formula))
11
11
  end
@@ -2,8 +2,8 @@ module Qlang
2
2
  module Parser
3
3
  module IntegralParser
4
4
  include Base
5
- def execute(string)
6
- integrated, range = string.scan(/S *\((.+)\)\[(.+)\]/).first
5
+ def execute(els)
6
+ integrated, range = els[0], els[1]
7
7
 
8
8
  integrated.rm!(' ')
9
9
 
@@ -2,9 +2,9 @@ module Qlang
2
2
  module Parser
3
3
  module MatrixParser
4
4
  include Base
5
- def execute(lexed_string, trans: false)
6
- lexed_string.rms!(')','(', 't')
7
- rows = lexed_string.split(/ *; */).map(&:split_by_sp)
5
+ def execute(els, opts={trans: false})
6
+ trans = opts[:trans]
7
+ rows = els.first.split(/ *(?:;|\n) */).map(&:split_by_sp)
8
8
  rows.all? { |row| row.count == rows.first.count }
9
9
  if trans
10
10
  rows = rows.transpose
@@ -2,10 +2,10 @@ module Qlang
2
2
  module Parser
3
3
  module VectorParser
4
4
  include Base
5
- def execute(lexed_string)
6
- lexed_string.rms!(/ *\( */, / *\) */)
7
- elements = lexed_string.split_by_sp
8
- VectorApi.execute(elements)
5
+ def execute(els)
6
+ VectorApi.execute(
7
+ els.first.rm(/\A +/).rm(/ +\z/).split_by_sp
8
+ )
9
9
  end
10
10
  module_function :execute
11
11
  end
@@ -1,3 +1,3 @@
1
1
  module Qlang
2
- VERSION = "0.0.27182000"
2
+ VERSION = "0.0.27182100"
3
3
  end
@@ -8,6 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Qlang::VERSION
9
9
  spec.authors = ['gogotanaka']
10
10
  spec.email = ['mail@tanakakazuki.com']
11
+ spec.extensions = ["ext/qlang/extconf.rb"]
11
12
  spec.summary = %q{Enjoy MATH!}
12
13
  spec.description = %q{Enjoy MATH!}
13
14
  spec.homepage = 'http://q-language.org/'
@@ -20,7 +21,8 @@ Gem::Specification.new do |spec|
20
21
 
21
22
  spec.add_dependency "dydx", '~> 0.1.41421'
22
23
 
23
- spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "bundler"
24
25
  spec.add_development_dependency "rake"
25
- spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "rake-compiler"
27
+ spec.add_development_dependency "minitest"
26
28
  end
@@ -0,0 +1,36 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestTokens < MiniTest::Unit::TestCase
4
+ include Qlang::Lexer::Tokens
5
+ def setup
6
+
7
+ end
8
+
9
+ def full_match(rgx, str)
10
+ assert_equal(0, rgx =~ str)
11
+ assert_equal(str, $&)
12
+ end
13
+
14
+ def not_match(rgx, str)
15
+ assert_equal(nil, rgx =~ str)
16
+ end
17
+
18
+ def test_nums
19
+ full_match(NUM, '1')
20
+ full_match(NUM, '234987423')
21
+ full_match(NUM, '23423948.298743')
22
+ full_match(NUM, 'e')
23
+ full_match(NUM, 'pi')
24
+ not_match(NUM, 'a')
25
+ end
26
+
27
+ def test_function
28
+ full_match(/[fgh]\(\w( ?, ?\w)*\) ?= ?[^\r\n]+/, 'f(x) = xy')
29
+ end
30
+
31
+ def test_differentiate
32
+ rgx = /d\/d[a-zA-Z] .*/
33
+ full_match(rgx, 'd/dx sin(x)')
34
+ full_match(rgx, 'd/dz z^2')
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ require 'qlang/iq'
2
+
3
+ class TestInterpreterBase < MiniTest::Unit::TestCase
4
+ # TODO: opposite
5
+ def assert_iq_equal(input, output)
6
+ assert_equal(Qlang::Iq.execute(input), output)
7
+ end
8
+
9
+ def assert_def_func(input, output)
10
+ assert_equal(Qlang::Iq.execute(input), output)
11
+ end
12
+
13
+ def assert_cal_func(input, output)
14
+ assert_equal(Qlang::Iq.execute(input), output)
15
+ reset
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestDifferential < TestInterpreterBase
4
+ def setup
5
+
6
+ end
7
+
8
+ def test_general
9
+ assert_iq_equal(
10
+ 'd/dx(e ** x)',
11
+ 'e ^ x'
12
+ )
13
+
14
+ assert_iq_equal(
15
+ 'd/dx(x ** 2)',
16
+ '2x'
17
+ )
18
+
19
+ assert_iq_equal(
20
+ 'd/dx(x * 2)',
21
+ '2'
22
+ )
23
+
24
+ assert_iq_equal(
25
+ 'd/dx( sin(x) )',
26
+ 'cos( x )'
27
+ )
28
+
29
+ assert_iq_equal(
30
+ 'd/dx(log( x ))',
31
+ '1 / x'
32
+ )
33
+
34
+ assert_iq_equal(
35
+ 'd/dx cos(x)',
36
+ '- sin( x )'
37
+ )
38
+
39
+ assert_iq_equal(
40
+ 'd/dx xx',
41
+ '2x'
42
+ )
43
+ end
44
+ end
@@ -0,0 +1,45 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestFunction < TestInterpreterBase
4
+ def setup
5
+
6
+ end
7
+
8
+ def test_general
9
+ assert_def_func('f(x, y) = x + y', 'x + y')
10
+ assert_cal_func('f( 4, 5 )', '9.0')
11
+
12
+ assert_def_func('f( x , y) = xy', 'x * y')
13
+ assert_cal_func('f( 3, 9 )', '27.0')
14
+
15
+ assert_def_func('f(x, y) = xy^2', 'x * ( y ** 2 )')
16
+ assert_cal_func('f( 3, 2 )', '12.0')
17
+
18
+ assert_def_func('f(x, y) = xy^2', 'x * ( y ** 2 )')
19
+ assert_cal_func('df/dx', 'y ^ 2')
20
+
21
+ assert_def_func('g(x) = x ^ 2', 'x ** 2')
22
+ assert_cal_func('g(2)', '4.0')
23
+
24
+ assert_def_func('h(x) = e ^ 2', 'e ** 2')
25
+ assert_cal_func('h(2)', '7.3890560989306495')
26
+
27
+ assert_def_func('h(x) = pix', 'pi * x')
28
+ assert_cal_func('h(3)', '9.42477796076938')
29
+
30
+ assert_def_func('h(x) = pie', 'pi * e')
31
+ assert_cal_func('h(2)', '8.539734222673566')
32
+
33
+ assert_def_func('h(x) = ( 1 / ( 2pi ) ^ ( 1 / 2.0 ) ) * e ^ ( - x ^ 2 / 2 )', '( ( 4503599627370496 / 6369051672525773 ) / ( pi ** 0.5 ) ) * ( e ** ( ( - ( x ** 2 ) ) / 2 ) )')
34
+ assert_cal_func('S( h(x)dx )[-oo..oo]', '1.0')
35
+
36
+ assert_def_func('f(x) = sin(x)', 'sin( x )')
37
+ assert_cal_func('f(pi)', '0.0')
38
+
39
+ assert_def_func('f(x) = cos(x)', 'cos( x )')
40
+ assert_cal_func('f(pi)', '-1.0')
41
+
42
+ assert_def_func('f(x) = log(x)', 'log( x )')
43
+ assert_cal_func('f(e)', '1.0')
44
+ end
45
+ end