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.
Files changed (41) hide show
  1. data/CHANGELOG.md +10 -2
  2. data/README.md +2 -1
  3. data/Rakefile +2 -2
  4. data/autotest/discover.rb +1 -0
  5. data/crisp.gemspec +32 -8
  6. data/examples/fibonacci.crisp +6 -0
  7. data/lib/crisp.rb +3 -1
  8. data/lib/crisp/chained_env.rb +13 -0
  9. data/lib/crisp/crisp.treetop +23 -15
  10. data/lib/crisp/env.rb +7 -0
  11. data/lib/crisp/function.rb +6 -42
  12. data/lib/crisp/function_runner.rb +37 -0
  13. data/lib/crisp/functions.rb +5 -3
  14. data/lib/crisp/functions/arithmetic.rb +64 -9
  15. data/lib/crisp/functions/core.rb +80 -18
  16. data/lib/crisp/native_call_invoker.rb +16 -0
  17. data/lib/crisp/nodes.rb +30 -59
  18. data/lib/crisp/nodes/array_literal.rb +21 -0
  19. data/lib/crisp/nodes/base.rb +22 -0
  20. data/lib/crisp/nodes/block.rb +22 -0
  21. data/lib/crisp/nodes/false_literal.rb +11 -0
  22. data/lib/crisp/nodes/float_literal.rb +11 -0
  23. data/lib/crisp/nodes/integer_literal.rb +11 -0
  24. data/lib/crisp/nodes/nil_literal.rb +11 -0
  25. data/lib/crisp/nodes/operation.rb +20 -0
  26. data/lib/crisp/nodes/primitive.rb +16 -0
  27. data/lib/crisp/nodes/string_literal.rb +11 -0
  28. data/lib/crisp/nodes/symbol_literal.rb +15 -0
  29. data/lib/crisp/nodes/true_literal.rb +11 -0
  30. data/lib/crisp/parser.rb +7 -0
  31. data/lib/crisp/runtime.rb +7 -0
  32. data/lib/crisp/shell.rb +4 -0
  33. data/spec/crisp/arithmetics_spec.rb +39 -11
  34. data/spec/crisp/basic_spec.rb +7 -72
  35. data/spec/crisp/core_spec.rb +83 -0
  36. data/spec/crisp/function_spec.rb +49 -0
  37. data/spec/crisp/internal_spec.rb +60 -0
  38. data/spec/crisp/native_call_invoker_spec.rb +23 -0
  39. data/spec/crisp/string_spec.rb +1 -1
  40. data/spec/spec_helper.rb +2 -0
  41. metadata +34 -10
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
- ## 0.0.6 (2010-xx-xx)
1
+ ## 0.0.8 (2010-xx-xx)
2
2
 
3
- * todo
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 is coming soon.
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.0'
18
- gem.add_development_dependency 'rspec', '~> 2.2.0'
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.5"
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-11-29}
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.0"])
62
- s.add_development_dependency(%q<rspec>, ["~> 2.2.0"])
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.0"])
65
- s.add_dependency(%q<rspec>, ["~> 2.2.0"])
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.0"])
69
- s.add_dependency(%q<rspec>, ["~> 2.2.0"])
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
 
@@ -0,0 +1,6 @@
1
+ (def fib (
2
+ fn [n]
3
+ (if (< n 2)
4
+ n
5
+ (+ (fib (- n 1)) (fib (- n 2))))))
6
+ (println "fibonacci for 10 is" (fib 10))
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.5'
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'
@@ -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
@@ -1,47 +1,55 @@
1
1
  grammar Crisp
2
2
 
3
3
  rule block
4
- (operation)* <Block>
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 / number / symbol / string / array
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]* <Symbol>
40
+ [a-z] [a-z0-9]* <Nodes::SymbolLiteral>
33
41
  end
34
42
 
35
- rule number
36
- '-'? ([1-9] [0-9]* / '0') <Number>
43
+ rule integer
44
+ '-'? ([1-9] [0-9]* / '0') <Nodes::IntegerLiteral>
37
45
  end
38
46
 
39
47
  rule float
40
- number '.' [0-9]* <Float>
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)
@@ -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
- def eval(env, params = [])
16
- @env = env
17
- @params = params
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
@@ -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
- def self.load(env)
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
- params_evaled.inject(:+)
8
- end.bind('+', env)
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
- params_evaled.inject(:-)
12
- end.bind('-', env)
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
- params_evaled.inject(:*)
16
- end.bind('*', env)
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
- params_evaled.inject(:/)
20
- end.bind('/', env)
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