calcula 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +5 -8
- data/lib/Expr.rb +32 -12
- data/lib/Exprs/AssignExpr.rb +39 -0
- data/lib/Exprs/BinopExpr.rb +53 -0
- data/lib/Exprs/BracedExpr.rb +48 -0
- data/lib/Exprs/FuncExpr.rb +31 -31
- data/lib/Exprs/IdentExpr.rb +25 -17
- data/lib/Exprs/NumExpr.rb +25 -17
- data/lib/Exprs/ParamsExpr.rb +24 -18
- data/lib/Exprs/RatExpr.rb +37 -0
- data/lib/Exprs/UnaryExpr.rb +84 -0
- data/lib/Lexer.rb +158 -119
- data/lib/Parser.rb +317 -40
- data/lib/Token.rb +23 -4
- data/lib/calcula.rb +79 -4
- data/lib/calcula/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 397e946ee023cbfbe15fbd3c78e7fda729e9fa41
|
4
|
+
data.tar.gz: ad9f8f5b4da62221b96e08e4ff3afd2887317f40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9017478c73db894b546a21bd0563a5e40cbca71281831223fe345b581a0d5c585791195fc1f10c988a413ba81715ddd792967c95882cca31cfe573e573a15817
|
7
|
+
data.tar.gz: f4033ce6ce081fbf36995db752a7f90c96844663949d78abdc5fa7846b4cef0e808728940dcce1a4bc1508f996c6fdb6092f7a69b7d08f9ab0136bca527c9778
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Calcula [![Build Status](https://travis-ci.org/plankp/Calcula.svg?branch=master)](https://travis-ci.org/plankp/Calcula) [![Inline docs](http://inch-ci.org/github/plankp/Calcula.svg?branch=master)](http://inch-ci.org/github/plankp/Calcula)
|
1
|
+
# Calcula [![Build Status](https://travis-ci.org/plankp/Calcula.svg?branch=master)](https://travis-ci.org/plankp/Calcula) [![Code Climate](https://codeclimate.com/github/plankp/Calcula/badges/gpa.svg)](https://codeclimate.com/github/plankp/Calcula) [![Inline docs](http://inch-ci.org/github/plankp/Calcula.svg?branch=master)](http://inch-ci.org/github/plankp/Calcula) [![Gem Version](https://badge.fury.io/rb/calcula.svg)](https://badge.fury.io/rb/calcula)
|
2
2
|
|
3
3
|
When mathematics meets programming
|
4
4
|
|
@@ -22,17 +22,14 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
26
|
-
To do so, type in:
|
25
|
+
To compile Calcula code to ruby, type in:
|
27
26
|
|
28
27
|
```ruby
|
29
28
|
require "calcula"
|
30
29
|
src = <<-'EOS'
|
31
|
-
# Write some
|
30
|
+
# Write some Calcula code here
|
32
31
|
EOS
|
33
|
-
|
34
|
-
puts tokens.collect { |e| e.text }.to_s
|
35
|
-
puts Calcula.parse(tokens).to_tree
|
32
|
+
puts Calcula::compile(src)
|
36
33
|
```
|
37
34
|
|
38
35
|
## Development
|
@@ -47,4 +44,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/plankp
|
|
47
44
|
|
48
45
|
## License
|
49
46
|
|
50
|
-
The gem is available as open source under the terms of the [MIT License](
|
47
|
+
The gem is available as open source under the terms of the [MIT License](./LICENSE.txt).
|
data/lib/Expr.rb
CHANGED
@@ -1,20 +1,40 @@
|
|
1
|
+
# @author Paul T.
|
1
2
|
module Calcula
|
2
|
-
class Expr
|
3
|
-
|
4
|
-
def to_s()
|
5
|
-
""
|
6
|
-
end
|
7
3
|
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
# All valid tree expression must be childrens of this class and should be
|
5
|
+
# placed under the module `Calcula::Exprs`
|
6
|
+
#
|
7
|
+
# @see Calcula::Exprs
|
8
|
+
# @abstract
|
9
|
+
# @author Paul T.
|
10
|
+
class Expr
|
11
11
|
|
12
|
-
#
|
13
|
-
|
14
|
-
|
12
|
+
# Converts the expression to a string. If the form is `:src`, then the
|
13
|
+
# resulting string should resemble as much as its source code as possible.
|
14
|
+
# If the form is `:tree`, the result string should resemble in a Lisp like
|
15
|
+
# form. If the form is `:ruby`, the result should be Ruby code that does the
|
16
|
+
# same thing. Otherwise, `nil` should be returned.
|
17
|
+
#
|
18
|
+
# @param form [Optional, Symbol] The type of format being converted into
|
19
|
+
# @return [String, nil] A string that resembles the specify form
|
20
|
+
def to_s(form: :src)
|
21
|
+
case form
|
22
|
+
when :src then
|
23
|
+
""
|
24
|
+
when :tree then
|
25
|
+
"()"
|
26
|
+
when :ruby then
|
27
|
+
""
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
15
31
|
end
|
16
32
|
|
17
|
-
|
33
|
+
# Returns the child nodes as a list. Child nodes must be transversible
|
34
|
+
# (hence also expressions).
|
35
|
+
#
|
36
|
+
# @return [Array<Calcula::Expr>] A list of transversible child nodes
|
37
|
+
def children
|
18
38
|
[]
|
19
39
|
end
|
20
40
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative "../Expr"
|
2
|
+
|
3
|
+
# Expression for assigning value to variables
|
4
|
+
#
|
5
|
+
# @author Paul T.
|
6
|
+
class Calcula::Exprs::AssignExpr < Calcula::Expr
|
7
|
+
|
8
|
+
# @param ident [Calcula::Exprs::IdentExpr]
|
9
|
+
# @param value [Calcula::Expr]
|
10
|
+
def initialize(ident, value)
|
11
|
+
@ident = ident
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
# @see Calcula::Expr#to_s
|
16
|
+
# @param (see Calcula::Expr#to_s)
|
17
|
+
# @return (see Calcula::Expr#to_s)
|
18
|
+
def to_s(form: :src)
|
19
|
+
identTxt = @ident.to_s(form: form)
|
20
|
+
valueTxt = @value.to_s(form: form)
|
21
|
+
case form
|
22
|
+
when :src then
|
23
|
+
"let #{identTxt}=#{valueTxt}"
|
24
|
+
when :tree then
|
25
|
+
"(let #{identTxt} #{valueTxt})"
|
26
|
+
when :ruby then
|
27
|
+
"#{identTxt} = #{valueTxt}"
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @see Calcula::Expr#children
|
34
|
+
# @param (see Calcula::Expr#children)
|
35
|
+
# @return (see Calcula::Expr#children)
|
36
|
+
def children
|
37
|
+
[@ident, @value]
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative "../Expr"
|
2
|
+
|
3
|
+
# Expression for binary operators. An expression 10(2) is also a binary operator.
|
4
|
+
# Its operator will be `:PAREN_O`
|
5
|
+
#
|
6
|
+
# @author Paul T.
|
7
|
+
class Calcula::Exprs::BinopExpr < Calcula::Expr
|
8
|
+
|
9
|
+
# @param op [Calcula::Token] Should have type prefixed with `OP_`
|
10
|
+
# @param left [Calcula::Expr]
|
11
|
+
# @param right [Calcula::Expr]
|
12
|
+
def initialize(op, left, right)
|
13
|
+
@op = op
|
14
|
+
@left = left
|
15
|
+
@right = right
|
16
|
+
end
|
17
|
+
|
18
|
+
# @see Calcula::Expr#to_s
|
19
|
+
# @param (see Calcula::Expr#to_s)
|
20
|
+
# @return (see Calcula::Expr#to_s)
|
21
|
+
def to_s(form: :src)
|
22
|
+
leftTxt = @left.to_s(form: form)
|
23
|
+
rightTxt = @right.to_s(form: form)
|
24
|
+
case form
|
25
|
+
when :src, :ruby then
|
26
|
+
case @op.id
|
27
|
+
when :PAREN_O then
|
28
|
+
"#{leftTxt}#{"." if form == :ruby}(#{rightTxt})"
|
29
|
+
when :OP_EQ then
|
30
|
+
"#{leftTxt}#{form == :ruby ? "==" : "="}#{rightTxt}"
|
31
|
+
when :AND then
|
32
|
+
"#{leftTxt}#{form == :ruby ? "&&" : " and "}#{rightTxt}"
|
33
|
+
when :OR then
|
34
|
+
"#{leftTxt}#{form == :ruby ? "||" : " or "}#{rightTxt}"
|
35
|
+
when :COMPOSE then
|
36
|
+
"->(*x){#{leftTxt}.(#{rightTxt}.(*x))}"
|
37
|
+
else
|
38
|
+
"#{leftTxt}#{@op.text}#{rightTxt}"
|
39
|
+
end
|
40
|
+
when :tree then
|
41
|
+
"(#{@op.text} #{leftTxt} #{rightTxt})"
|
42
|
+
else
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @see Calcula::Expr#children
|
48
|
+
# @param (see Calcula::Expr#children)
|
49
|
+
# @return (see Calcula::Expr#children)
|
50
|
+
def children
|
51
|
+
[@left, @right]
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "../Expr"
|
2
|
+
|
3
|
+
# Expression for bracket operators. Floor operators also count as bracket
|
4
|
+
# operators.
|
5
|
+
#
|
6
|
+
# @author Paul T.
|
7
|
+
class Calcula::Exprs::BracedExpr < Calcula::Expr
|
8
|
+
|
9
|
+
# @param startTok [Calcula::Token] The starting token of this expression
|
10
|
+
# @param endTok [Calcula::Token] The ending token of this expression
|
11
|
+
# @param inner [Calcula::Expr]
|
12
|
+
def initialize(startTok, endTok, inner)
|
13
|
+
@startTok = startTok
|
14
|
+
@endTok = endTok
|
15
|
+
@inner = inner
|
16
|
+
end
|
17
|
+
|
18
|
+
# @see Calcula::Expr#to_s
|
19
|
+
# @param (see Calcula::Expr#to_s)
|
20
|
+
# @return (see Calcula::Expr#to_s)
|
21
|
+
def to_s(form: :src)
|
22
|
+
innerTxt = @inner.to_s(form: form)
|
23
|
+
case form
|
24
|
+
when :src then
|
25
|
+
"#{@startTok.text}#{innerTxt}#{@endTok.text}"
|
26
|
+
when :tree then
|
27
|
+
"#{@startTok.text} #{innerTxt} #{@endTok.text}"
|
28
|
+
when :ruby then
|
29
|
+
case @startTok.id
|
30
|
+
when :PAREN_O then
|
31
|
+
"(#{innerTxt})"
|
32
|
+
when :SQUARE_O then
|
33
|
+
"(#{innerTxt}).floor.to_r"
|
34
|
+
else
|
35
|
+
raise "Unknown delimiter #{@startTok.id}"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @see Calcula::Expr#children
|
43
|
+
# @param (see Calcula::Expr#children)
|
44
|
+
# @return (see Calcula::Expr#children)
|
45
|
+
def children
|
46
|
+
[@inner]
|
47
|
+
end
|
48
|
+
end
|
data/lib/Exprs/FuncExpr.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
1
|
require_relative "../Expr"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
# Expression for functions and lambda expression
|
4
|
+
#
|
5
|
+
# @author Paul T.
|
6
|
+
class Calcula::Exprs::FuncExpr < Calcula::Expr
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def to_s()
|
14
|
-
return "\\#{@params.to_s}(#{@action.to_s})" if @name == nil
|
15
|
-
return "#{@name.to_s}(#{@params.to_s})=#{@action.to_s}"
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_tree()
|
19
|
-
return "(lambda #{@params.to_tree} #{@action.to_tree})" if @name == nil
|
20
|
-
return "(func #{@name.to_tree} #{@params.to_tree} #{@action.to_tree})"
|
21
|
-
end
|
22
|
-
|
23
|
-
def exec(binding)
|
24
|
-
if @name == nil then
|
25
|
-
# We return it (its a lambda function afterall...)
|
26
|
-
else
|
27
|
-
# We do not invoke this function. We just add it to the `binding`
|
28
|
-
end
|
29
|
-
end
|
8
|
+
# @param params [Calcula::Exprs::ParamsExpr] Parameters to the function
|
9
|
+
# @param action [Calcula::Expr] The body of the function
|
10
|
+
def initialize(params, action)
|
11
|
+
@params = params
|
12
|
+
@action = action
|
13
|
+
end
|
30
14
|
|
31
|
-
|
32
|
-
|
15
|
+
# @see Calcula::Expr#to_s
|
16
|
+
# @param (see Calcula::Expr#to_s)
|
17
|
+
# @return (see Calcula::Expr#to_s)
|
18
|
+
def to_s(form: :src)
|
19
|
+
paramsTxt = @params.to_s(form: form)
|
20
|
+
actionTxt = @action.to_s(form: form)
|
21
|
+
case form
|
22
|
+
when :src then
|
23
|
+
"\\#{paramsTxt}(#{actionTxt})"
|
24
|
+
when :tree then
|
25
|
+
"(lambda #{paramsTxt} #{actionTxt})"
|
26
|
+
when :ruby then
|
27
|
+
"->#{paramsTxt}{#{actionTxt}}"
|
28
|
+
else
|
29
|
+
nil
|
33
30
|
end
|
31
|
+
end
|
34
32
|
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
# @see Calcula::Expr#children
|
34
|
+
# @param (see Calcula::Expr#children)
|
35
|
+
# @return (see Calcula::Expr#children)
|
36
|
+
def children
|
37
|
+
[@params, @action]
|
38
38
|
end
|
39
39
|
end
|
data/lib/Exprs/IdentExpr.rb
CHANGED
@@ -1,27 +1,35 @@
|
|
1
1
|
require_relative "../Expr"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
# Expression for identifiers
|
4
|
+
#
|
5
|
+
# @author Paul T.
|
6
|
+
class Calcula::Exprs::IdentExpr < Calcula::Expr
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
# @param name [Calcula::Token] This token should have the type ID
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
end
|
10
12
|
|
11
|
-
|
13
|
+
# @see Calcula::Expr#to_s
|
14
|
+
# @param (see Calcula::Expr#to_s)
|
15
|
+
# @return (see Calcula::Expr#to_s)
|
16
|
+
def to_s(form: :src)
|
17
|
+
case form
|
18
|
+
when :src then
|
12
19
|
@name.text
|
13
|
-
|
14
|
-
|
15
|
-
def to_tree()
|
20
|
+
when :tree then
|
16
21
|
"(ident #{@name.text})"
|
22
|
+
when :ruby then
|
23
|
+
@name.text.tr("'", "_")
|
24
|
+
else
|
25
|
+
nil
|
17
26
|
end
|
27
|
+
end
|
18
28
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
[]
|
25
|
-
end
|
29
|
+
# @see Calcula::Expr#children
|
30
|
+
# @param (see Calcula::Expr#children)
|
31
|
+
# @return (see Calcula::Expr#children)
|
32
|
+
def children
|
33
|
+
[]
|
26
34
|
end
|
27
35
|
end
|
data/lib/Exprs/NumExpr.rb
CHANGED
@@ -1,27 +1,35 @@
|
|
1
1
|
require_relative "../Expr"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
# Expression for representing real numbers
|
4
|
+
#
|
5
|
+
# @author Paul T.
|
6
|
+
class Calcula::Exprs::NumExpr < Calcula::Expr
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
# @param num [Calcula::Token] The token should have the type of NUM
|
9
|
+
def initialize(num)
|
10
|
+
@num = num
|
11
|
+
end
|
10
12
|
|
11
|
-
|
13
|
+
# @see Calcula::Expr#to_s
|
14
|
+
# @param (see Calcula::Expr#to_s)
|
15
|
+
# @return (see Calcula::Expr#to_s)
|
16
|
+
def to_s(form: :src)
|
17
|
+
case form
|
18
|
+
when :src then
|
12
19
|
@num.text
|
13
|
-
|
14
|
-
|
15
|
-
def to_tree()
|
20
|
+
when :tree then
|
16
21
|
"(num #{@num.text})"
|
22
|
+
when :ruby then
|
23
|
+
"#{@num.text}r"
|
24
|
+
else
|
25
|
+
nil
|
17
26
|
end
|
27
|
+
end
|
18
28
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
[]
|
25
|
-
end
|
29
|
+
# @see Calcula::Expr#children
|
30
|
+
# @param (see Calcula::Expr#children)
|
31
|
+
# @return (see Calcula::Expr#children)
|
32
|
+
def children
|
33
|
+
[]
|
26
34
|
end
|
27
35
|
end
|