Module: JSE::Functors::Lisp

Defined in:
lib/jse/functors/lisp.rb

Constant Summary collapse

LISP_FUNCTORS =
{
  "$eval"   => method(:eval_fn),
  "$apply"  => method(:apply_fn),
  "$lambda" => method(:lambda_fn),
  "$def"    => method(:def_fn),
  "$defn"   => method(:defn),
}.freeze

Class Method Summary collapse

Class Method Details

.apply_fn(env, *args) ⇒ Object



9
10
11
12
13
14
15
# File 'lib/jse/functors/lisp.rb', line 9

def self.apply_fn(env, *args)
  raise "$apply requires (functor, arglist)" if args.length < 2
  functor = args[0].respond_to?(:apply) ? env.eval(args[0]) : args[0]
  arglist = args[1].respond_to?(:apply) ? env.eval(args[1]) : args[1]
  raise "$apply second argument must be a list" unless arglist.is_a?(Array)
  functor.call(env, *arglist)
end

.def_fn(env, *args) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/jse/functors/lisp.rb', line 35

def self.def_fn(env, *args)
  raise "$def requires (name, value)" if args.length < 2
  name_node = args[0]
  name = if name_node.is_a?(Ast::SymbolNode)
    name_node.name
  elsif name_node.is_a?(String)
    name_node
  else
    name_node.to_s
  end
  value = args[1].respond_to?(:apply) ? env.eval(args[1]) : args[1]
  env.register(name, value)
  value
end

.defn(env, *args) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/jse/functors/lisp.rb', line 50

def self.defn(env, *args)
  raise "$defn requires (name, params, body)" if args.length < 3
  name_node = args[0]
  name = if name_node.is_a?(Ast::SymbolNode)
    name_node.name
  else
    name_node.to_s
  end
  lambda_result = lambda_fn(env, args[1], args[2])
  env.register(name, lambda_result)
  lambda_result
end

.eval_fn(env, *args) ⇒ Object



4
5
6
7
# File 'lib/jse/functors/lisp.rb', line 4

def self.eval_fn(env, *args)
  raise "$eval requires 1 argument" if args.empty?
  env.eval(args[0])
end

.lambda_fn(env, *args) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/jse/functors/lisp.rb', line 17

def self.lambda_fn(env, *args)
  raise "$lambda requires (params, body)" if args.length < 2
  params_raw = args[0]
  body = args[1]

  params = if params_raw.is_a?(Ast::ArrayNode)
    params_raw.elements.map { |e| e.is_a?(Ast::SymbolNode) ? e.name : e }
  elsif params_raw.is_a?(Ast::SymbolNode)
    [params_raw.name]
  elsif params_raw.is_a?(Array)
    params_raw
  else
    [params_raw.to_s]
  end

  Ast::LambdaNode.new(params, body, env)
end