crisp 0.0.5 → 0.0.7
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.
- data/CHANGELOG.md +10 -2
- data/README.md +2 -1
- data/Rakefile +2 -2
- data/autotest/discover.rb +1 -0
- data/crisp.gemspec +32 -8
- data/examples/fibonacci.crisp +6 -0
- data/lib/crisp.rb +3 -1
- data/lib/crisp/chained_env.rb +13 -0
- data/lib/crisp/crisp.treetop +23 -15
- data/lib/crisp/env.rb +7 -0
- data/lib/crisp/function.rb +6 -42
- data/lib/crisp/function_runner.rb +37 -0
- data/lib/crisp/functions.rb +5 -3
- data/lib/crisp/functions/arithmetic.rb +64 -9
- data/lib/crisp/functions/core.rb +80 -18
- data/lib/crisp/native_call_invoker.rb +16 -0
- data/lib/crisp/nodes.rb +30 -59
- data/lib/crisp/nodes/array_literal.rb +21 -0
- data/lib/crisp/nodes/base.rb +22 -0
- data/lib/crisp/nodes/block.rb +22 -0
- data/lib/crisp/nodes/false_literal.rb +11 -0
- data/lib/crisp/nodes/float_literal.rb +11 -0
- data/lib/crisp/nodes/integer_literal.rb +11 -0
- data/lib/crisp/nodes/nil_literal.rb +11 -0
- data/lib/crisp/nodes/operation.rb +20 -0
- data/lib/crisp/nodes/primitive.rb +16 -0
- data/lib/crisp/nodes/string_literal.rb +11 -0
- data/lib/crisp/nodes/symbol_literal.rb +15 -0
- data/lib/crisp/nodes/true_literal.rb +11 -0
- data/lib/crisp/parser.rb +7 -0
- data/lib/crisp/runtime.rb +7 -0
- data/lib/crisp/shell.rb +4 -0
- data/spec/crisp/arithmetics_spec.rb +39 -11
- data/spec/crisp/basic_spec.rb +7 -72
- data/spec/crisp/core_spec.rb +83 -0
- data/spec/crisp/function_spec.rb +49 -0
- data/spec/crisp/internal_spec.rb +60 -0
- data/spec/crisp/native_call_invoker_spec.rb +23 -0
- data/spec/crisp/string_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- metadata +34 -10
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
-
## 0.0.
|
1
|
+
## 0.0.8 (2010-xx-xx)
|
2
2
|
|
3
|
-
*
|
3
|
+
* ...
|
4
|
+
|
5
|
+
## 0.0.6/0.0.7 (2010-12-17)
|
6
|
+
|
7
|
+
* if else statements
|
8
|
+
* compare functions
|
9
|
+
* basic support for ruby method invokation (thanks to invadersmustdie)
|
10
|
+
* supplied first examples
|
11
|
+
* refactored internals and specs
|
4
12
|
|
5
13
|
## 0.0.5 (2010-11-29)
|
6
14
|
|
data/README.md
CHANGED
@@ -8,6 +8,7 @@ The main purpose of the language is to deal with the issues and problems when cr
|
|
8
8
|
|
9
9
|
### Example
|
10
10
|
|
11
|
+
# crisp
|
11
12
|
>> (* 2 3)
|
12
13
|
=> 6
|
13
14
|
>> (def foo 4)
|
@@ -21,7 +22,7 @@ The main purpose of the language is to deal with the issues and problems when cr
|
|
21
22
|
|
22
23
|
### Installation
|
23
24
|
|
24
|
-
gem
|
25
|
+
gem install crisp
|
25
26
|
|
26
27
|
### Usage
|
27
28
|
|
data/Rakefile
CHANGED
@@ -14,8 +14,8 @@ begin
|
|
14
14
|
gem.email = "github@mgsnova.de"
|
15
15
|
gem.homepage = "http://github.com/mgsnova/crisp"
|
16
16
|
gem.authors = ['Markus Gerdes']
|
17
|
-
gem.add_dependency 'treetop', '~> 1.4.
|
18
|
-
gem.add_development_dependency 'rspec', '~> 2.
|
17
|
+
gem.add_dependency 'treetop', '~> 1.4.9'
|
18
|
+
gem.add_development_dependency 'rspec', '~> 2.3.0'
|
19
19
|
end
|
20
20
|
|
21
21
|
Jeweler::GemcutterTasks.new
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { 'rspec2' }
|
data/crisp.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{crisp}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Markus Gerdes"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-12-17}
|
13
13
|
s.default_executable = %q{crisp}
|
14
14
|
s.email = %q{github@mgsnova.de}
|
15
15
|
s.executables = ["crisp"]
|
@@ -22,23 +22,43 @@ Gem::Specification.new do |s|
|
|
22
22
|
"LICENSE",
|
23
23
|
"README.md",
|
24
24
|
"Rakefile",
|
25
|
+
"autotest/discover.rb",
|
25
26
|
"bin/crisp",
|
26
27
|
"crisp.gemspec",
|
28
|
+
"examples/fibonacci.crisp",
|
27
29
|
"lib/crisp.rb",
|
28
30
|
"lib/crisp/chained_env.rb",
|
29
31
|
"lib/crisp/crisp.treetop",
|
30
32
|
"lib/crisp/env.rb",
|
31
33
|
"lib/crisp/errors.rb",
|
32
34
|
"lib/crisp/function.rb",
|
35
|
+
"lib/crisp/function_runner.rb",
|
33
36
|
"lib/crisp/functions.rb",
|
34
37
|
"lib/crisp/functions/arithmetic.rb",
|
35
38
|
"lib/crisp/functions/core.rb",
|
39
|
+
"lib/crisp/native_call_invoker.rb",
|
36
40
|
"lib/crisp/nodes.rb",
|
41
|
+
"lib/crisp/nodes/array_literal.rb",
|
42
|
+
"lib/crisp/nodes/base.rb",
|
43
|
+
"lib/crisp/nodes/block.rb",
|
44
|
+
"lib/crisp/nodes/false_literal.rb",
|
45
|
+
"lib/crisp/nodes/float_literal.rb",
|
46
|
+
"lib/crisp/nodes/integer_literal.rb",
|
47
|
+
"lib/crisp/nodes/nil_literal.rb",
|
48
|
+
"lib/crisp/nodes/operation.rb",
|
49
|
+
"lib/crisp/nodes/primitive.rb",
|
50
|
+
"lib/crisp/nodes/string_literal.rb",
|
51
|
+
"lib/crisp/nodes/symbol_literal.rb",
|
52
|
+
"lib/crisp/nodes/true_literal.rb",
|
37
53
|
"lib/crisp/parser.rb",
|
38
54
|
"lib/crisp/runtime.rb",
|
39
55
|
"lib/crisp/shell.rb",
|
40
56
|
"spec/crisp/arithmetics_spec.rb",
|
41
57
|
"spec/crisp/basic_spec.rb",
|
58
|
+
"spec/crisp/core_spec.rb",
|
59
|
+
"spec/crisp/function_spec.rb",
|
60
|
+
"spec/crisp/internal_spec.rb",
|
61
|
+
"spec/crisp/native_call_invoker_spec.rb",
|
42
62
|
"spec/crisp/string_spec.rb",
|
43
63
|
"spec/spec_helper.rb"
|
44
64
|
]
|
@@ -49,6 +69,10 @@ Gem::Specification.new do |s|
|
|
49
69
|
s.test_files = [
|
50
70
|
"spec/crisp/arithmetics_spec.rb",
|
51
71
|
"spec/crisp/basic_spec.rb",
|
72
|
+
"spec/crisp/core_spec.rb",
|
73
|
+
"spec/crisp/function_spec.rb",
|
74
|
+
"spec/crisp/internal_spec.rb",
|
75
|
+
"spec/crisp/native_call_invoker_spec.rb",
|
52
76
|
"spec/crisp/string_spec.rb",
|
53
77
|
"spec/spec_helper.rb"
|
54
78
|
]
|
@@ -58,15 +82,15 @@ Gem::Specification.new do |s|
|
|
58
82
|
s.specification_version = 3
|
59
83
|
|
60
84
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
61
|
-
s.add_runtime_dependency(%q<treetop>, ["~> 1.4.
|
62
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.
|
85
|
+
s.add_runtime_dependency(%q<treetop>, ["~> 1.4.9"])
|
86
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
63
87
|
else
|
64
|
-
s.add_dependency(%q<treetop>, ["~> 1.4.
|
65
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
88
|
+
s.add_dependency(%q<treetop>, ["~> 1.4.9"])
|
89
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
66
90
|
end
|
67
91
|
else
|
68
|
-
s.add_dependency(%q<treetop>, ["~> 1.4.
|
69
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
92
|
+
s.add_dependency(%q<treetop>, ["~> 1.4.9"])
|
93
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
70
94
|
end
|
71
95
|
end
|
72
96
|
|
data/lib/crisp.rb
CHANGED
@@ -3,7 +3,7 @@ require "treetop"
|
|
3
3
|
require "pp"
|
4
4
|
|
5
5
|
module Crisp
|
6
|
-
VERSION = '0.0.
|
6
|
+
VERSION = '0.0.7'
|
7
7
|
end
|
8
8
|
|
9
9
|
require 'crisp/errors'
|
@@ -13,5 +13,7 @@ require 'crisp/chained_env'
|
|
13
13
|
require 'crisp/env'
|
14
14
|
require 'crisp/nodes'
|
15
15
|
require 'crisp/function'
|
16
|
+
require 'crisp/function_runner'
|
16
17
|
require 'crisp/functions'
|
17
18
|
require 'crisp/shell'
|
19
|
+
require 'crisp/native_call_invoker'
|
data/lib/crisp/chained_env.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
1
|
module Crisp
|
2
|
+
# The ChainedEnv combines to given environments.
|
3
|
+
# This is useful to combine a global and a local environment for easy access
|
4
|
+
#
|
2
5
|
class ChainedEnv
|
6
|
+
# creates new chained env with given envs
|
7
|
+
# It is used that the 'first' is the local and the 'second' the global env
|
3
8
|
def initialize(first, second)
|
4
9
|
@first = first
|
5
10
|
@second = second
|
6
11
|
end
|
7
12
|
|
13
|
+
# Returns boolean for existence of given key in one of the environments.
|
14
|
+
def has_key?(key)
|
15
|
+
@first.has_key?(key) or @second.has_key?(key)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Read access is performed preferred on the 'first' env.
|
19
|
+
# If the 'first' env is not holding a value for the key, the 'second' will be requested.
|
8
20
|
def [](key)
|
9
21
|
if @first.has_key?(key)
|
10
22
|
@first[key]
|
@@ -13,6 +25,7 @@ module Crisp
|
|
13
25
|
end
|
14
26
|
end
|
15
27
|
|
28
|
+
# Storing a value for a key will always be performed on the 'second' env.
|
16
29
|
def []=(key, val)
|
17
30
|
@second[key] = val
|
18
31
|
end
|
data/lib/crisp/crisp.treetop
CHANGED
@@ -1,47 +1,55 @@
|
|
1
1
|
grammar Crisp
|
2
2
|
|
3
3
|
rule block
|
4
|
-
(
|
4
|
+
(func_identifier / element)* <Nodes::Block>
|
5
5
|
end
|
6
6
|
|
7
7
|
rule operation
|
8
|
-
space paren_start space func_identifier element_list:(space element)* space paren_end space <Operation>
|
8
|
+
space paren_start space func_identifier element_list:(space element)* space paren_end space <Nodes::Operation>
|
9
9
|
end
|
10
10
|
|
11
11
|
rule array
|
12
|
-
array_paren_start element_list:(space element)* space array_paren_end <ArrayLiteral>
|
12
|
+
array_paren_start element_list:(space element)* space array_paren_end <Nodes::ArrayLiteral>
|
13
13
|
end
|
14
14
|
|
15
15
|
rule element
|
16
|
-
operation / float /
|
16
|
+
true / false / nil / operation / float / integer / symbol / string / array
|
17
17
|
end
|
18
18
|
|
19
19
|
rule func_identifier
|
20
20
|
symbol
|
21
21
|
/
|
22
|
-
|
22
|
+
[/=*<>\-+\.]
|
23
23
|
/
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
'
|
24
|
+
operation
|
25
|
+
end
|
26
|
+
|
27
|
+
rule true
|
28
|
+
'true' <Nodes::TrueLiteral>
|
29
|
+
end
|
30
|
+
|
31
|
+
rule false
|
32
|
+
'false' <Nodes::FalseLiteral>
|
33
|
+
end
|
34
|
+
|
35
|
+
rule nil
|
36
|
+
'nil' <Nodes::NilLiteral>
|
29
37
|
end
|
30
38
|
|
31
39
|
rule symbol
|
32
|
-
[a-z] [a-z0-9]* <
|
40
|
+
[a-z] [a-z0-9]* <Nodes::SymbolLiteral>
|
33
41
|
end
|
34
42
|
|
35
|
-
rule
|
36
|
-
'-'? ([1-9] [0-9]* / '0') <
|
43
|
+
rule integer
|
44
|
+
'-'? ([1-9] [0-9]* / '0') <Nodes::IntegerLiteral>
|
37
45
|
end
|
38
46
|
|
39
47
|
rule float
|
40
|
-
|
48
|
+
integer '.' [0-9]* <Nodes::FloatLiteral>
|
41
49
|
end
|
42
50
|
|
43
51
|
rule string
|
44
|
-
'"' [^"]* '"' <StringLiteral>
|
52
|
+
'"' [^"]* '"' <Nodes::StringLiteral>
|
45
53
|
end
|
46
54
|
|
47
55
|
rule space
|
data/lib/crisp/env.rb
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
module Crisp
|
2
|
+
# The Crisp environment is basically a key/value store.
|
3
|
+
# The value for each key is immutable, so you can only store one time for each key
|
2
4
|
class Env
|
5
|
+
# create a new internal hash
|
3
6
|
def initialize
|
4
7
|
@map = {}
|
5
8
|
end
|
6
9
|
|
10
|
+
# Returns boolean for existence of given key in the environment.
|
7
11
|
def has_key?(key)
|
8
12
|
@map.has_key?(key.to_sym)
|
9
13
|
end
|
10
14
|
|
15
|
+
# Returns the value for the given key.
|
11
16
|
def [](key)
|
12
17
|
@map[key.to_sym]
|
13
18
|
end
|
14
19
|
|
20
|
+
# Store the key/value pair.
|
21
|
+
# It is only possible to store a value for a key once, otherwise a error will be raised.
|
15
22
|
def []=(key, val)
|
16
23
|
key = key.to_sym
|
17
24
|
raise EnvironmentError, "#{key} already binded" if @map.has_key?(key)
|
data/lib/crisp/function.rb
CHANGED
@@ -1,59 +1,23 @@
|
|
1
1
|
module Crisp
|
2
|
+
# The Crisp function
|
2
3
|
class Function
|
3
4
|
attr_reader :name
|
4
5
|
|
6
|
+
# create new function by calling new with a code block
|
5
7
|
def initialize(&blk)
|
6
8
|
@name = nil
|
7
9
|
@blk = blk
|
8
10
|
end
|
9
11
|
|
12
|
+
# bind the function to the given name in the given environment
|
10
13
|
def bind(name, env)
|
11
14
|
@name = name.to_sym
|
12
15
|
env[name] = self
|
13
16
|
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
@
|
18
|
-
self.instance_eval(&@blk)
|
19
|
-
end
|
20
|
-
|
21
|
-
protected
|
22
|
-
|
23
|
-
def validate_params_count(expected, got)
|
24
|
-
if expected != got
|
25
|
-
raise ArgumentError, "wrong number of arguments for '#{name}' (#{got} for #{expected})"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def params_values
|
30
|
-
params.map do |param|
|
31
|
-
param.eval(env)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def params_evaled
|
36
|
-
params_values.map do |param|
|
37
|
-
if param.class.to_s == 'Symbol'
|
38
|
-
if env[param].respond_to?(:eval)
|
39
|
-
env[param].eval(env)
|
40
|
-
else
|
41
|
-
env[param]
|
42
|
-
end
|
43
|
-
else
|
44
|
-
param
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def env
|
52
|
-
@env
|
53
|
-
end
|
54
|
-
|
55
|
-
def params
|
56
|
-
@params
|
18
|
+
# evaluate the function by using the given environment and argument list
|
19
|
+
def eval(env, args = [])
|
20
|
+
FunctionRunner.run(@blk, env, args, name)
|
57
21
|
end
|
58
22
|
end
|
59
23
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Crisp
|
2
|
+
# The FunctionRunner can eval function calls by instance_eval the function block
|
3
|
+
class FunctionRunner
|
4
|
+
attr_reader :name, :args, :env
|
5
|
+
|
6
|
+
# run the blk
|
7
|
+
def self.run(blk, env, args, name)
|
8
|
+
runner = new(env, args, name)
|
9
|
+
runner.instance_eval(&blk)
|
10
|
+
end
|
11
|
+
|
12
|
+
# save name, environment and arguments on creation
|
13
|
+
def initialize(env, args, name)
|
14
|
+
@name = name
|
15
|
+
@env = env
|
16
|
+
@args = args
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
# following methods are used for calling from the function block
|
21
|
+
|
22
|
+
# raise an error if argument count got does not match the expected
|
23
|
+
def validate_args_count(expected, got)
|
24
|
+
if (expected.is_a?(Numeric) and expected != got) or
|
25
|
+
(expected.is_a?(Range) and !(expected === got))
|
26
|
+
raise ArgumentError, "wrong number of arguments for '#{name}' (#{got} for #{expected})"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# returns the resolved/evaled argument list
|
31
|
+
def args_evaled
|
32
|
+
args.map do |arg|
|
33
|
+
arg.resolve_and_eval(env)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/crisp/functions.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
require 'crisp/functions/core'
|
2
|
-
require 'crisp/functions/arithmetic'
|
3
|
-
|
4
1
|
module Crisp
|
5
2
|
module Functions
|
3
|
+
# require all files that are defining functions
|
4
|
+
require 'crisp/functions/core'
|
5
|
+
require 'crisp/functions/arithmetic'
|
6
|
+
|
7
|
+
# Load all defined function to the given environment
|
6
8
|
def self.load(env)
|
7
9
|
Core.load(env)
|
8
10
|
Arithmetic.load(env)
|
@@ -1,23 +1,78 @@
|
|
1
1
|
module Crisp
|
2
2
|
module Functions
|
3
|
+
# Defining arithemtic crisp functions
|
3
4
|
class Arithmetic
|
4
|
-
|
5
|
+
# load the functions and bind them into the given environment
|
6
|
+
def self.load(current_env)
|
5
7
|
|
8
|
+
# +
|
9
|
+
# sum up all arguments
|
10
|
+
#
|
11
|
+
# (+ 1 2 3)
|
12
|
+
# => 6
|
6
13
|
Function.new do
|
7
|
-
|
8
|
-
end.bind('+',
|
14
|
+
args_evaled.inject(:+)
|
15
|
+
end.bind('+', current_env)
|
9
16
|
|
17
|
+
# -
|
18
|
+
# substract all arguments
|
19
|
+
#
|
20
|
+
# (- 5 2 1)
|
21
|
+
# => 2
|
10
22
|
Function.new do
|
11
|
-
|
12
|
-
end.bind('-',
|
23
|
+
args_evaled.inject(:-)
|
24
|
+
end.bind('-', current_env)
|
13
25
|
|
26
|
+
# *
|
27
|
+
# multiply all arguments
|
28
|
+
#
|
29
|
+
# (* 2 3 4)
|
30
|
+
# => 24
|
14
31
|
Function.new do
|
15
|
-
|
16
|
-
end.bind('*',
|
32
|
+
args_evaled.inject(:*)
|
33
|
+
end.bind('*', current_env)
|
17
34
|
|
35
|
+
# /
|
36
|
+
# divide all arguments
|
37
|
+
#
|
38
|
+
# (/ 20 2 2)
|
39
|
+
# => 5
|
18
40
|
Function.new do
|
19
|
-
|
20
|
-
end.bind('/',
|
41
|
+
args_evaled.inject(:/)
|
42
|
+
end.bind('/', current_env)
|
43
|
+
|
44
|
+
# =
|
45
|
+
# compare 2 arguments for equality
|
46
|
+
#
|
47
|
+
# (= 1 2)
|
48
|
+
# => false
|
49
|
+
Function.new do
|
50
|
+
validate_args_count(2, args.size)
|
51
|
+
values = args_evaled
|
52
|
+
values[0] == values[1]
|
53
|
+
end.bind('=', current_env)
|
54
|
+
|
55
|
+
# >
|
56
|
+
# compare 2 arguments for being greater than the other
|
57
|
+
#
|
58
|
+
# (> 2 1)
|
59
|
+
# => true
|
60
|
+
Function.new do
|
61
|
+
validate_args_count(2, args.size)
|
62
|
+
values = args_evaled
|
63
|
+
values[0] > values[1]
|
64
|
+
end.bind('>', current_env)
|
65
|
+
|
66
|
+
# <
|
67
|
+
# compare 2 arguments for being less than the other
|
68
|
+
#
|
69
|
+
# (< 2 1)
|
70
|
+
# => false
|
71
|
+
Function.new do
|
72
|
+
validate_args_count(2, args.size)
|
73
|
+
values = args_evaled
|
74
|
+
values[0] < values[1]
|
75
|
+
end.bind('<', current_env)
|
21
76
|
|
22
77
|
end
|
23
78
|
end
|