bakkdoor-blocktalk 0.1.1 → 0.1.2
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/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
|