bakkdoor-blocktalk 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +165 -0
- data/README.markdown +114 -0
- data/TODO +9 -0
- data/benchmark.bt +18 -0
- data/evaluator.rb +19 -0
- data/examples/chained_method_call.bt +15 -0
- data/examples/classes_modules.bt +68 -0
- data/examples/exceptions.bt +28 -0
- data/examples/fac.bt +23 -0
- data/examples/inline_ruby.bt +20 -0
- data/examples/linecounter.bt +8 -0
- data/examples/multiple_methodcall.bt +1 -0
- data/examples/portscan.bt +39 -0
- data/examples/require.bt +8 -0
- data/examples/ruby_methods.bt +20 -0
- data/examples/string_interpol.bt +10 -0
- data/examples/string_test.bt +13 -0
- data/examples/test.bt +45 -0
- data/examples/test2.bt +125 -0
- data/examples/test3.bt +9 -0
- data/grammar/blocktalk.rb +5030 -0
- data/grammar/blocktalk.tt +463 -0
- data/language-spec/blocktalk-example.bt +38 -0
- data/language-spec/blocktalk-lang-spec.bt +232 -0
- data/lib/blocktalk/array.bt +60 -0
- data/lib/blocktalk/string.bt +9 -0
- data/lib/blocktalk.bt +3 -0
- data/lib/core.rb +12 -0
- data/lib/kernel/array.rb +9 -0
- data/lib/kernel/class.rb +46 -0
- data/lib/kernel/codeblock.rb +57 -0
- data/lib/kernel/console.rb +40 -0
- data/lib/kernel/error.rb +11 -0
- data/lib/kernel/module.rb +18 -0
- data/lib/kernel/object.rb +66 -0
- data/lib/kernel/string.rb +5 -0
- data/lib/kernel/system.rb +5 -0
- data/parser/helpers/method_definitions.rb +31 -0
- data/parser/helpers/methodcalls.rb +56 -0
- data/parser/nodes/block_literal.rb +42 -0
- data/parser/nodes/catch.rb +22 -0
- data/parser/nodes/class_method_definition.rb +15 -0
- data/parser/nodes/comment.rb +7 -0
- data/parser/nodes/ensure.rb +7 -0
- data/parser/nodes/expression.rb +7 -0
- data/parser/nodes/identifier.rb +7 -0
- data/parser/nodes/integer_literal.rb +7 -0
- data/parser/nodes/message_receiver.rb +7 -0
- data/parser/nodes/message_with_params.rb +8 -0
- data/parser/nodes/message_without_params.rb +10 -0
- data/parser/nodes/method_definition.rb +31 -0
- data/parser/nodes/methodcall.rb +37 -0
- data/parser/nodes/multiple_methodcall.rb +28 -0
- data/parser/nodes/operator_message.rb +8 -0
- data/parser/nodes/require.rb +25 -0
- data/parser/nodes/return.rb +7 -0
- data/parser/nodes/root.rb +15 -0
- data/parser/nodes/string.rb +7 -0
- data/parser/nodes/subexpression.rb +7 -0
- data/parser/nodes/super_call.rb +12 -0
- data/parser/nodes/try.rb +7 -0
- data/parser/nodes/yield.rb +18 -0
- data/parser/nodes.rb +29 -0
- metadata +70 -3
@@ -0,0 +1,232 @@
|
|
1
|
+
# 'blocktalk' language specification
|
2
|
+
# comments work like this
|
3
|
+
# or like this:
|
4
|
+
|
5
|
+
#-#
|
6
|
+
multiline comments look like this
|
7
|
+
#-#
|
8
|
+
|
9
|
+
# simple anonymous function definition.
|
10
|
+
# functions / procedures / methods in general are simply names
|
11
|
+
# to which anonymous methods / codeblocks are bound.
|
12
|
+
# in contrast to ruby, there is no difference between lambdas, procs & blocks.
|
13
|
+
foo = do |bar baz|
|
14
|
+
bar puts # sending message puts to object bar
|
15
|
+
end
|
16
|
+
|
17
|
+
# square is a function, that takes one argument (x)
|
18
|
+
# and returns the square of it.
|
19
|
+
# note: as in ruby, message is a expression-based language,
|
20
|
+
# so no explicit return statement is needed.
|
21
|
+
# the last expression gets returned implicitly.
|
22
|
+
square = do |x|
|
23
|
+
x * x
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# creating a subclass of Object called Integer.
|
28
|
+
# if no super class specified to constructor, Object is taken.
|
29
|
+
Class in: Integer do
|
30
|
+
# include Numerical module (as in ruby):
|
31
|
+
include Numerical
|
32
|
+
|
33
|
+
# operators are simply methods / messages that a class can define however it wants.
|
34
|
+
# in this case, the * operator is defined to be a message with one parameter (y).
|
35
|
+
def * = do |y|
|
36
|
+
|
37
|
+
# |> is a special operator that allows the last expression in a line above this one to be used
|
38
|
+
# as the argument to a method call.
|
39
|
+
# this makes it easier to handle several methodcalls to an object, retrieved in a more complex expression
|
40
|
+
# without needing to save it to a local variable or whatever.
|
41
|
+
|
42
|
+
(y is_a?: Number)
|
43
|
+
|> if_true do
|
44
|
+
# this gets executed, if the upper condition (boolean) object is true
|
45
|
+
(y is_a?: Integer) if_true do
|
46
|
+
Math base_int_mult: self with: y # some base function defined in the vm or whatever (in this case in the Math module)
|
47
|
+
end
|
48
|
+
|
49
|
+
(y is_a?: Float) if_true do
|
50
|
+
Math base_float_mult: self with: y
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|> if_false do
|
55
|
+
# raise an exception:
|
56
|
+
Error raise: (WrongArgumentError new: "Expected a number, but got #{y class}")
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
Class in: File deriving: Stream do
|
64
|
+
# constructor that takes a file handle given by the operating system or so.
|
65
|
+
def new = do |file_handle|
|
66
|
+
File new: (file_handle file_name) mode: (file_handle access_mode)
|
67
|
+
end
|
68
|
+
|
69
|
+
# constructor to File class
|
70
|
+
def new = do |file_name mode|
|
71
|
+
@file_name = file_name
|
72
|
+
@access_mode = mode
|
73
|
+
|
74
|
+
block_given?
|
75
|
+
|> if_true do
|
76
|
+
File open: file_name mode: mode do |f|
|
77
|
+
yield f
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# class method with named parameter.
|
83
|
+
# gets calles like this:
|
84
|
+
# File open "foo.txt" with:"r" do |f|
|
85
|
+
# Console puts : f readlines
|
86
|
+
# end
|
87
|
+
self open = do |file_name mode=nil|
|
88
|
+
mode ||= "r"
|
89
|
+
block_given? if_true do
|
90
|
+
# trying method takes a block (between { and }).
|
91
|
+
# this would also work: trying do ... end (same as in ruby).
|
92
|
+
# in ruby: trying = begin.
|
93
|
+
try {
|
94
|
+
# open file etc.
|
95
|
+
file = File new: (IO base_file_open: file_name mode)
|
96
|
+
# yield to block
|
97
|
+
yield: [file]
|
98
|
+
|
99
|
+
# catching errors is easy.
|
100
|
+
# simply use catch method with a given block to execute
|
101
|
+
# if the specified class (as the parameter) is caugth.
|
102
|
+
catch: IOError do |ex|
|
103
|
+
Console puts: "Error while trying to open file #{file_name} with access mode: #{mode}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Error is baseclass of all exceptions -> this will get called when all the others didn't match
|
107
|
+
catch: Error do |ex|
|
108
|
+
Console puts: "Error: #{ex}"
|
109
|
+
end
|
110
|
+
|
111
|
+
# blocks to methodcalls can also be done via curly-braces syntax {} (instead of do ... end)
|
112
|
+
ensure {
|
113
|
+
file close # always close the file
|
114
|
+
}
|
115
|
+
}
|
116
|
+
# and finally close again
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# ... more methods for File class go here ...
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
# Numerical - Module.
|
126
|
+
# Holds some basic mathematical messages that can be used by different numerical types.
|
127
|
+
Module in: Numerical do
|
128
|
+
|
129
|
+
def abs = {
|
130
|
+
(self > 0)
|
131
|
+
|> if_true { self }
|
132
|
+
|> if_false { self * -1 }
|
133
|
+
}
|
134
|
+
|
135
|
+
def ** = { |power|
|
136
|
+
((abs power) == 0) if_true { return 1 }
|
137
|
+
|
138
|
+
return self * (self ** (power - 1))
|
139
|
+
}
|
140
|
+
|
141
|
+
def expt = (**) # define expt to be the same as **
|
142
|
+
|
143
|
+
def - = {
|
144
|
+
self * -1
|
145
|
+
}
|
146
|
+
|
147
|
+
def negate = (-)
|
148
|
+
|
149
|
+
def fac = {
|
150
|
+
(self <= 1) if_true { return 1 }
|
151
|
+
self * ((self - 1) fac)
|
152
|
+
}
|
153
|
+
|
154
|
+
# maybe some more ...
|
155
|
+
|
156
|
+
def incr = { self += 1 }
|
157
|
+
def decr = { self -= 1 }
|
158
|
+
|
159
|
+
def ++ = { self incr }
|
160
|
+
|
161
|
+
def -- = { self decr }
|
162
|
+
|
163
|
+
def to = do |n|
|
164
|
+
block_given? if_true {
|
165
|
+
i = self
|
166
|
+
msg = (incr)
|
167
|
+
|
168
|
+
(i > n) if_true {
|
169
|
+
msg = (decr)
|
170
|
+
}
|
171
|
+
|
172
|
+
(i != n) while_true {
|
173
|
+
yield i
|
174
|
+
i msg # increment or decrement i, based on value of msg
|
175
|
+
}
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def times = {
|
180
|
+
i = self
|
181
|
+
(i > 0) while_true {
|
182
|
+
i decr
|
183
|
+
yield i
|
184
|
+
}
|
185
|
+
}
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
Class in: Boolean do
|
191
|
+
|
192
|
+
def if_true = {
|
193
|
+
# check (via some core routine in the vm) if self == true.
|
194
|
+
# if so: yield to block.
|
195
|
+
# finally, return self for easy chaining.
|
196
|
+
yield
|
197
|
+
self
|
198
|
+
}
|
199
|
+
|
200
|
+
def if_false = {
|
201
|
+
# similar to if_true, but only yield, if self == false.
|
202
|
+
yield
|
203
|
+
self
|
204
|
+
}
|
205
|
+
|
206
|
+
def while_true = {
|
207
|
+
self if_true {
|
208
|
+
yield
|
209
|
+
self while_true
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
def while_true = {
|
214
|
+
self if_false {
|
215
|
+
yield
|
216
|
+
self while_false
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
Module in: MyModule {
|
224
|
+
def self some_static_method = do |param1 and: param2|
|
225
|
+
return "bla_blubb"
|
226
|
+
end
|
227
|
+
}
|
228
|
+
|
229
|
+
|
230
|
+
Class in: Foo deriving: [Bar] {
|
231
|
+
self mixin: [Enumerable, Weirdo]
|
232
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
Class >> :Array do
|
2
|
+
%ruby{
|
3
|
+
alias_method :insert_original, :insert
|
4
|
+
alias_method :push_original, :push
|
5
|
+
alias_method :unshift_original, :unshift
|
6
|
+
alias_method :values_at_original, :values_at
|
7
|
+
alias_method :zip_original, :zip
|
8
|
+
}%
|
9
|
+
|
10
|
+
def rest = do
|
11
|
+
%ruby{
|
12
|
+
self[0..-1]
|
13
|
+
}%
|
14
|
+
end
|
15
|
+
|
16
|
+
def at = do |index put: value|
|
17
|
+
%ruby{
|
18
|
+
self[index] = value
|
19
|
+
}%
|
20
|
+
end
|
21
|
+
|
22
|
+
def insert = do |index_obj_arr|
|
23
|
+
%ruby{
|
24
|
+
self.insert_original(*index_obj_arr.flatten)
|
25
|
+
}%
|
26
|
+
end
|
27
|
+
|
28
|
+
def push = do |obj_arr|
|
29
|
+
%ruby{
|
30
|
+
if obj_arr.is_a?(Array)
|
31
|
+
self.push_original(*obj_arr)
|
32
|
+
else
|
33
|
+
self.push_original(obj_arr)
|
34
|
+
end
|
35
|
+
}%
|
36
|
+
end
|
37
|
+
|
38
|
+
def unshift = do |obj_arr|
|
39
|
+
%ruby{
|
40
|
+
if obj_arr.is_a?(Array)
|
41
|
+
self.unshift_original(*obj_arr)
|
42
|
+
else
|
43
|
+
self.unshift_original(obj_arr)
|
44
|
+
end
|
45
|
+
}%
|
46
|
+
end
|
47
|
+
|
48
|
+
def values_at = do |selector_arr|
|
49
|
+
%ruby{
|
50
|
+
self.values_at_original(*selector_arr)
|
51
|
+
}%
|
52
|
+
end
|
53
|
+
|
54
|
+
def zip = do |arg_arr|
|
55
|
+
%ruby{
|
56
|
+
self.zip_original(*arg_arr)
|
57
|
+
}%
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/lib/blocktalk.bt
ADDED
data/lib/core.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# expand search path correct subdir.
|
2
|
+
$: << File.expand_path(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require "kernel/array"
|
5
|
+
require "kernel/class"
|
6
|
+
require "kernel/codeblock"
|
7
|
+
require "kernel/console"
|
8
|
+
require "kernel/error"
|
9
|
+
require "kernel/module"
|
10
|
+
require "kernel/object"
|
11
|
+
require "kernel/string"
|
12
|
+
require "kernel/system"
|
data/lib/kernel/array.rb
ADDED
data/lib/kernel/class.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
class Class
|
2
|
+
def self.in(class_name_sym, &block)
|
3
|
+
self.in__subclassing(class_name_sym, Object, &block)
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.in__subclassing(class_name_sym, superclass = Object, &block)
|
7
|
+
# try to find class via const_get
|
8
|
+
# if error occurs (not found), define a new class with the given name
|
9
|
+
begin
|
10
|
+
classobj = Kernel::const_get(class_name_sym)
|
11
|
+
classobj.class_eval(&block)
|
12
|
+
rescue
|
13
|
+
Kernel::const_set(class_name_sym, Class.new(superclass, &block))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.>>(class_name_sym, &block)
|
18
|
+
class_name = class_name_sym
|
19
|
+
superclass = Object # default
|
20
|
+
|
21
|
+
if class_name_sym.is_a?(Hash)
|
22
|
+
class_name = class_name_sym.keys.first
|
23
|
+
superclass = class_name_sym.values.first
|
24
|
+
end
|
25
|
+
|
26
|
+
self.in__subclassing(class_name, superclass, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def extend(&block)
|
30
|
+
self.class_eval(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def mixin(modules = [])
|
34
|
+
modules.each do |m|
|
35
|
+
self.class_eval do
|
36
|
+
include m
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def meta_class
|
42
|
+
class << self
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Kernel
|
2
|
+
class Codeblock < Proc
|
3
|
+
|
4
|
+
attr_reader :params, :block
|
5
|
+
|
6
|
+
def initialize(params = [], &block)
|
7
|
+
if params.size > 0 && (params.size != block.arity)
|
8
|
+
raise "Error: Codeblock's arity doesn't match given argument list."
|
9
|
+
else
|
10
|
+
super(&block)
|
11
|
+
@params = params
|
12
|
+
@block = block
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(*args)
|
17
|
+
calling_args = []
|
18
|
+
args.rest.each do |arg_name_with_val|
|
19
|
+
name, val = arg_name_with_val
|
20
|
+
if name && val
|
21
|
+
pos = param_pos(name)
|
22
|
+
puts "pos: #{pos}"
|
23
|
+
calling_args[pos] = val
|
24
|
+
end
|
25
|
+
end
|
26
|
+
if calling_args.size > 0
|
27
|
+
super(*([args.first] + calling_args))
|
28
|
+
else
|
29
|
+
super(*args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def param_pos(param_name)
|
34
|
+
if @params.include?(param_name)
|
35
|
+
@params.index(param_name)
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def while_true(&block)
|
42
|
+
while self.call
|
43
|
+
block.call
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def while_false(&block)
|
48
|
+
while not self.call
|
49
|
+
block.call
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def until(&block)
|
54
|
+
self.while_false(&block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Console
|
2
|
+
def self.puts(*args)
|
3
|
+
Kernel::puts *args
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.print(*args)
|
7
|
+
Kernel::print *args
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.putc(*args)
|
11
|
+
Kernel::putc(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.printf(arg_array)
|
15
|
+
Kernel::printf(*arg_array)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.write(*args)
|
19
|
+
Kernel::print(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.writeln(*args)
|
23
|
+
Kernel::puts(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.gets(prompt_str = nil)
|
27
|
+
if prompt_str
|
28
|
+
self.print(prompt_str.to_s + " ")
|
29
|
+
end
|
30
|
+
Kernel::gets
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.readln(prompt_str = nil)
|
34
|
+
gets(prompt_str)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.clear
|
38
|
+
puts "\e[H\e[2J"
|
39
|
+
end
|
40
|
+
end
|
data/lib/kernel/error.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Module
|
2
|
+
def self.in(module_name_sym, &block)
|
3
|
+
if Kernel::constants.include?(module_name_sym.to_s)
|
4
|
+
moduleobj = Kernel::const_get(module_name_sym)
|
5
|
+
moduleobj.module_eval(&block)
|
6
|
+
else
|
7
|
+
Kernel::const_set(module_name_sym, Module.new(&block))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.>>(module_name_sym, &block)
|
12
|
+
self.in(module_name_sym, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def extend(&block)
|
16
|
+
self.module_eval(&block)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
def if_true(true_block = nil)
|
4
|
+
if self == true
|
5
|
+
if true_block
|
6
|
+
true_block.call
|
7
|
+
elsif block_given?
|
8
|
+
yield
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def if_true__if_false(true_block = nil, false_block = nil)
|
14
|
+
if self == true
|
15
|
+
if true_block
|
16
|
+
true_block.call
|
17
|
+
elsif block_given?
|
18
|
+
yield
|
19
|
+
end
|
20
|
+
else
|
21
|
+
if false_block
|
22
|
+
false_block.call
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def if_false(&block)
|
28
|
+
if self == false
|
29
|
+
block.call
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def if(&block)
|
34
|
+
if self
|
35
|
+
block.call
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def unless(&block)
|
40
|
+
unless self
|
41
|
+
block.call
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# this should get called, if we try to call a method on objects of
|
46
|
+
# ruby classes.
|
47
|
+
# it will try to find the correct ruby method-name & clall it.
|
48
|
+
def method_missing(name, *args, &block)
|
49
|
+
# probably a blocktalk_like method was called, when we actually
|
50
|
+
# ment a ruby method
|
51
|
+
splitted = name.to_s.split("__")
|
52
|
+
if splitted.size == 2
|
53
|
+
ruby_name = splitted.first
|
54
|
+
|
55
|
+
# hopefully, we got it right
|
56
|
+
# to make us not do the work again simply create the method for
|
57
|
+
# later use and then call it
|
58
|
+
arg_names = 0.upto(args.size - 1).collect{|i| "arg_#{i}"}
|
59
|
+
self.instance_eval "def #{name}(#{arg_names.join(',')}, &block); self.send(:#{ruby_name}, #{arg_names.join(',')}, &block); end;"
|
60
|
+
# now call!
|
61
|
+
self.send(ruby_name, *args, &block)
|
62
|
+
else
|
63
|
+
raise "Unknown method, don't know what to do: #{self.class}##{name}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Blocktalk
|
2
|
+
module ASTHelpers
|
3
|
+
module MethodDefinitions
|
4
|
+
def ruby_method(method_name, params)
|
5
|
+
params_val = params.value
|
6
|
+
method_name_val = method_name.value
|
7
|
+
|
8
|
+
bang_or_question = nil
|
9
|
+
|
10
|
+
# check for bang or boolean methods (!/? at the end)
|
11
|
+
if method_name.text_value =~ /(!|\?)/
|
12
|
+
method_name_val = method_name_val[0..-2]
|
13
|
+
bang_or_question = method_name.text_value[-1].chr.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
param_names = params_val.collect{|p| p[:name].to_s[1..-1] if p[:name]}.reject{|p| p.nil?}
|
17
|
+
# methods with more than one parameter have names including
|
18
|
+
# the additional param-names, e.g.:
|
19
|
+
# def goto = do |place with: vehicle| ... end
|
20
|
+
# becomes: def goto_with(place, vehicle) ... end
|
21
|
+
if param_names.size > 0
|
22
|
+
method_name_val += "__" + param_names.join("__")
|
23
|
+
end
|
24
|
+
|
25
|
+
method_name_val += bang_or_question if bang_or_question
|
26
|
+
|
27
|
+
return method_name_val
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Blocktalk
|
2
|
+
module ASTHelpers
|
3
|
+
module Methodcalls
|
4
|
+
def generate_methodcall(receiver, message, passed_block = nil)
|
5
|
+
message_hash = message.value
|
6
|
+
message = message_hash[:message]
|
7
|
+
param_names = message_hash[:params].collect{|p| p.is_a?(Hash) ? p[:name] : nil}
|
8
|
+
param_values = message_hash[:params].collect{|p| p.is_a?(Hash) ? p[:value] : p.value}
|
9
|
+
message += param_names.join("__")
|
10
|
+
|
11
|
+
if message =~ /new_\S*/
|
12
|
+
message = "new"
|
13
|
+
end
|
14
|
+
|
15
|
+
# this happens, when we pass in a chained method call
|
16
|
+
# the string then is the already evaluated part of the chain...
|
17
|
+
eval_str = ""
|
18
|
+
if receiver.is_a?(String)
|
19
|
+
eval_str += "#{receiver}.#{message}("
|
20
|
+
else
|
21
|
+
eval_str += "#{receiver.value}.#{message}("
|
22
|
+
end
|
23
|
+
eval_str += "#{param_values.join(', ')}"
|
24
|
+
|
25
|
+
if passed_block && passed_block.class == Blocktalk::BlockLiteralNode
|
26
|
+
eval_str += "){" # start block
|
27
|
+
|
28
|
+
# check for block_params
|
29
|
+
if passed_block.params.respond_to?(:value)
|
30
|
+
eval_str += "|"
|
31
|
+
eval_str +=
|
32
|
+
passed_block.params.value.collect{|p| p[:identifier]}.join(",")
|
33
|
+
eval_str += "| "
|
34
|
+
end
|
35
|
+
|
36
|
+
eval_str += passed_block.body.value # insert block-body
|
37
|
+
eval_str += "}" # end block
|
38
|
+
|
39
|
+
elsif passed_block && passed_block.text_value =~ /&\S+/
|
40
|
+
# check for Proc-Objects passed to method as block
|
41
|
+
if params.size > 0
|
42
|
+
eval_str += ", "
|
43
|
+
end
|
44
|
+
eval_str += "&"
|
45
|
+
eval_str += passed_block.block_var_name.value
|
46
|
+
eval_str += ")"
|
47
|
+
else
|
48
|
+
# no block given -> method call is finished
|
49
|
+
eval_str += ")"
|
50
|
+
end
|
51
|
+
|
52
|
+
return eval_str
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|