qlang 0.0.27182000 → 0.0.27182100

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