bakkdoor-blocktalk 0.1.4 → 0.1.5
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/README.markdown +14 -14
- data/examples/conditionals.bt +37 -0
- data/examples/literals.bt +8 -0
- data/examples/webserver.bt +145 -0
- data/grammar/blocktalk.rb +25 -11
- data/grammar/blocktalk.tt +2 -2
- data/lib/blocktalk.bt +2 -0
- data/lib/blocktalk/hash.bt +13 -0
- data/lib/kernel/codeblock.rb +16 -2
- data/parser/nodes/string.rb +1 -1
- metadata +5 -2
- data/version.rb +0 -3
data/README.markdown
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# ***Blocktalk*** #
|
|
2
|
-
### **v0.1.
|
|
2
|
+
### **v0.1.5** ###
|
|
3
3
|
|
|
4
4
|
## **Blocktalk** is a dynamic, object-oriented programming language somewhat in the tradition of Smalltalk and Ruby. ##
|
|
5
5
|
|
|
@@ -15,8 +15,8 @@ For example, defining classes and modules in Blocktalk is also done via methodca
|
|
|
15
15
|
respectively:
|
|
16
16
|
|
|
17
17
|
Class >> :Foo do
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
def bar = do |baz|
|
|
19
|
+
Console puts: "In Foo#bar with baz = #{baz}"
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
@@ -41,9 +41,9 @@ can take two explicit codeblocks for a if and then part, or just a block for the
|
|
|
41
41
|
or implicitly as a ruby-like method call with a passed in block):
|
|
42
42
|
|
|
43
43
|
(a < b) if_true: {
|
|
44
|
-
|
|
44
|
+
Console print: "a smaller than b!"
|
|
45
45
|
} if_false: {
|
|
46
|
-
|
|
46
|
+
Console print: "a greater than b!"
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
Since Blocktalk supports a very easy literal syntax for codeblocks, many special keywords aren't needed (as in Smalltalk).
|
|
@@ -53,8 +53,8 @@ Another example would be a while loop:
|
|
|
53
53
|
|
|
54
54
|
i = Console gets: "Please enter a number!" to_i
|
|
55
55
|
{i < 10} while_true {
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
Console print: "a smaller than b!"
|
|
57
|
+
i = Console gets: "Enter again!" to_i
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
In this case, while_true takes a ruby-like implicit block, noticeable by the absence of the colon after the methodname,
|
|
@@ -68,15 +68,15 @@ Exception handling in Blocktalk is done similar to most programming languages, i
|
|
|
68
68
|
|
|
69
69
|
i = Console gets: "Please enter a number!"
|
|
70
70
|
try {
|
|
71
|
-
|
|
71
|
+
Console print: "10 / i = #{(10 / (i to_i))}"
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
catch: ZeroDivisionError do |ex|
|
|
74
|
+
Console print: "got a exception: #{ex message}"
|
|
75
|
+
end
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
ensure {
|
|
78
|
+
Console print: "this will get done, no matter what value i has!"
|
|
79
|
+
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
This example will obviously fail if the we enter a zero. As in Ruby, the ensure-block gets run independent of an error
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
x = 10
|
|
2
|
+
y = 0
|
|
3
|
+
|
|
4
|
+
{
|
|
5
|
+
y = Console gets: "please enter a positive number:" to_i
|
|
6
|
+
} until {y > 0}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
x <= y if_true: {
|
|
10
|
+
Console puts: "x (#{x}) <= y (#{y})!"
|
|
11
|
+
} if_false: {
|
|
12
|
+
Console puts: "x (#{x}) > y (#{y})!"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Console puts
|
|
16
|
+
|
|
17
|
+
# blocktalk also supports the if / unless at the end, as in ruby
|
|
18
|
+
{ Console puts: "x (#{x}) <= y (#{y})!" } if: (x <= y)
|
|
19
|
+
{ Console puts: "x (#{x}) > y (#{y})!"} if: (x > y)
|
|
20
|
+
|
|
21
|
+
Console puts
|
|
22
|
+
|
|
23
|
+
# this would also work:
|
|
24
|
+
{ Console puts: "x (#{x}) > y (#{y})!" } unless: (x <= y)
|
|
25
|
+
|
|
26
|
+
Console puts
|
|
27
|
+
|
|
28
|
+
x = 0
|
|
29
|
+
{x < 10} while_true {
|
|
30
|
+
Console puts: x
|
|
31
|
+
x = x + 1
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
{x < 0} while_false {
|
|
35
|
+
Console puts: x
|
|
36
|
+
x = x - 1
|
|
37
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# small working webserver example
|
|
2
|
+
# taken, translated & changed a bit from:
|
|
3
|
+
# http://blogs.msdn.com/abhinaba/archive/2005/10/14/ruby-webserver-in-70-lines-of-code.aspx
|
|
4
|
+
|
|
5
|
+
System require: "socket"
|
|
6
|
+
require: "lib/blocktalk"
|
|
7
|
+
|
|
8
|
+
Class >> :Logger do
|
|
9
|
+
def initialize = do |logfile|
|
|
10
|
+
@log_file = logfile
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def log = do |message|
|
|
14
|
+
Console puts: "\n\n";
|
|
15
|
+
puts: ("=" * 50);
|
|
16
|
+
puts: "\n #{message}"
|
|
17
|
+
|
|
18
|
+
(@log_file == nil) if_false {
|
|
19
|
+
@log_file puts: "\n\n";
|
|
20
|
+
puts: ("=" * 50);
|
|
21
|
+
puts: "\n #{message}"
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Class >> :Webserver do
|
|
27
|
+
def initialize = do |session request: req root_path: root_path|
|
|
28
|
+
@session = session
|
|
29
|
+
@request = req
|
|
30
|
+
@root_path = root_path
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def full_path = do
|
|
34
|
+
filename = nil
|
|
35
|
+
(@request =~ /GET (.*) HTTP.*/) if {
|
|
36
|
+
filename = $1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
(filename == nil) unless {
|
|
40
|
+
filename = @root_path + filename
|
|
41
|
+
filename = File expand_path: filename with: @default_path
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
(File directory?: filename) if {
|
|
45
|
+
filename << '/index.html'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return filename
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def serve = do
|
|
52
|
+
Console puts: "trying to serve content"
|
|
53
|
+
@full_path = self full_path
|
|
54
|
+
src = nil
|
|
55
|
+
try{
|
|
56
|
+
((File exist?: @full_path) and: (File file?: @full_path)) if_true: {
|
|
57
|
+
Console puts: "File exists: #{@full_path}"
|
|
58
|
+
# path should start with base path
|
|
59
|
+
((@full_path index: @root_path) == 0) if_true: {
|
|
60
|
+
content_type = self content_type: @full_path
|
|
61
|
+
@session print: "HTTP/1.1 200/OK\r\nServer: Blocktalk-HTTP\r\nContent-type: #{content_type}\r\n\r\n"
|
|
62
|
+
src = File open: @full_path mode: "rb"
|
|
63
|
+
|
|
64
|
+
{src eof?} while_false {
|
|
65
|
+
buffer = src read: 256
|
|
66
|
+
@session write: buffer
|
|
67
|
+
}
|
|
68
|
+
src close
|
|
69
|
+
src = nil
|
|
70
|
+
} if_false: {
|
|
71
|
+
# should have sent a 403 Forbidden access but then the attacker knows that such a file exists
|
|
72
|
+
@session print: "HTTP/1.1 404/Object Not Found\r\nServer: Blocktalk-HTTP\r\n\r\n"
|
|
73
|
+
}
|
|
74
|
+
} if_false: {
|
|
75
|
+
Console puts: "Error: File doesnt exist: #{@full_path}"
|
|
76
|
+
@session print: "HTTP/1.1 404/Object Not Found\r\nServer: Blocktalk-HTTP\r\n\r\n"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
catch: StandardError do |ex|
|
|
80
|
+
Console puts: "OOPS: #{ex inspect}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
ensure{
|
|
84
|
+
(src nil?) if_false {
|
|
85
|
+
src close
|
|
86
|
+
}
|
|
87
|
+
@session close
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def content_types = do
|
|
93
|
+
{
|
|
94
|
+
".html" => "text/html",
|
|
95
|
+
".htm" => "text/html",
|
|
96
|
+
".txt" => "text/plain",
|
|
97
|
+
".css" => "text/css",
|
|
98
|
+
".jpeg" => "image/jpeg",
|
|
99
|
+
".jpg" => "image/jpeg",
|
|
100
|
+
".gif" => "image/gif",
|
|
101
|
+
".bmp" => "image/bmp",
|
|
102
|
+
".rb" => "text/plain",
|
|
103
|
+
".xml" => "text/xml",
|
|
104
|
+
".xsl" => "text/xml"
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def content_type = do |path|
|
|
109
|
+
ext = File extname: path
|
|
110
|
+
type = self content_types at: ext
|
|
111
|
+
|
|
112
|
+
(type nil?) if_true {
|
|
113
|
+
type = "text/html"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return type
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
root_path = "/home/bakkdoor/projekte/blocktalk/webserver/httpd/"
|
|
121
|
+
logfile_name = root_path + "/log.txt"
|
|
122
|
+
|
|
123
|
+
File open: logfile_name mode: "w+" do |logfile|
|
|
124
|
+
port = 3000
|
|
125
|
+
{port = ARGV at: 0} if: (ARGV at: 0)
|
|
126
|
+
|
|
127
|
+
server = TCPServer new: 'localhost' port: port
|
|
128
|
+
logger = Logger new: logfile
|
|
129
|
+
|
|
130
|
+
Kernel loop do
|
|
131
|
+
session = server accept
|
|
132
|
+
request = session gets
|
|
133
|
+
logStr = "#{session peeraddr at: 2} (#{session peeraddr at: 3})\n"
|
|
134
|
+
logStr = logStr + (Time now localtime strftime: "%Y/%m/%d %H:%M:%S")
|
|
135
|
+
logStr = logStr + "\n#{request}"
|
|
136
|
+
logger log: logStr
|
|
137
|
+
|
|
138
|
+
Console puts: "OK"
|
|
139
|
+
|
|
140
|
+
Thread start: session with: request do |session request|
|
|
141
|
+
ws = Webserver new: session request: request root_path: root_path
|
|
142
|
+
ws serve
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
data/grammar/blocktalk.rb
CHANGED
|
@@ -3015,6 +3015,7 @@ module Blocktalk
|
|
|
3015
3015
|
def pair
|
|
3016
3016
|
elements[2]
|
|
3017
3017
|
end
|
|
3018
|
+
|
|
3018
3019
|
end
|
|
3019
3020
|
|
|
3020
3021
|
module HashLiteral1
|
|
@@ -3037,7 +3038,7 @@ module Blocktalk
|
|
|
3037
3038
|
first_pair = first_entry.value
|
|
3038
3039
|
hash_str += "#{first_pair[0]} => #{first_pair[1]},"
|
|
3039
3040
|
rest_pairs.elements.each do |ws_and_pair|
|
|
3040
|
-
pair = ws_and_pair.pair
|
|
3041
|
+
pair = ws_and_pair.pair.value
|
|
3041
3042
|
hash_str += "#{pair[0]} => #{pair[1]},"
|
|
3042
3043
|
end
|
|
3043
3044
|
hash_str += "}"
|
|
@@ -3123,6 +3124,19 @@ module Blocktalk
|
|
|
3123
3124
|
if r11
|
|
3124
3125
|
r13 = _nt_hash_entry
|
|
3125
3126
|
s9 << r13
|
|
3127
|
+
if r13
|
|
3128
|
+
s14, i14 = [], index
|
|
3129
|
+
loop do
|
|
3130
|
+
r15 = _nt_ws
|
|
3131
|
+
if r15
|
|
3132
|
+
s14 << r15
|
|
3133
|
+
else
|
|
3134
|
+
break
|
|
3135
|
+
end
|
|
3136
|
+
end
|
|
3137
|
+
r14 = instantiate_node(SyntaxNode,input, i14...index, s14)
|
|
3138
|
+
s9 << r14
|
|
3139
|
+
end
|
|
3126
3140
|
end
|
|
3127
3141
|
end
|
|
3128
3142
|
if s9.last
|
|
@@ -3141,26 +3155,26 @@ module Blocktalk
|
|
|
3141
3155
|
r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
|
|
3142
3156
|
s0 << r8
|
|
3143
3157
|
if r8
|
|
3144
|
-
|
|
3158
|
+
s16, i16 = [], index
|
|
3145
3159
|
loop do
|
|
3146
|
-
|
|
3147
|
-
if
|
|
3148
|
-
|
|
3160
|
+
r17 = _nt_ws
|
|
3161
|
+
if r17
|
|
3162
|
+
s16 << r17
|
|
3149
3163
|
else
|
|
3150
3164
|
break
|
|
3151
3165
|
end
|
|
3152
3166
|
end
|
|
3153
|
-
|
|
3154
|
-
s0 <<
|
|
3155
|
-
if
|
|
3167
|
+
r16 = instantiate_node(SyntaxNode,input, i16...index, s16)
|
|
3168
|
+
s0 << r16
|
|
3169
|
+
if r16
|
|
3156
3170
|
if input.index('}', index) == index
|
|
3157
|
-
|
|
3171
|
+
r18 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
|
3158
3172
|
@index += 1
|
|
3159
3173
|
else
|
|
3160
3174
|
terminal_parse_failure('}')
|
|
3161
|
-
|
|
3175
|
+
r18 = nil
|
|
3162
3176
|
end
|
|
3163
|
-
s0 <<
|
|
3177
|
+
s0 << r18
|
|
3164
3178
|
end
|
|
3165
3179
|
end
|
|
3166
3180
|
end
|
data/grammar/blocktalk.tt
CHANGED
|
@@ -270,7 +270,7 @@ grammar Blocktalk do
|
|
|
270
270
|
|
|
271
271
|
rule hash_literal do
|
|
272
272
|
# '{' ws* '}' /
|
|
273
|
-
'{' ws* first_entry:(hash_entry)? ws* rest_pairs:(',' ws* pair:(hash_entry))* ws* '}' {
|
|
273
|
+
'{' ws* first_entry:(hash_entry)? ws* rest_pairs:(',' ws* pair:(hash_entry) ws*)* ws* '}' {
|
|
274
274
|
def value
|
|
275
275
|
if self.text_value =~ /\{\s*\}/
|
|
276
276
|
return "{}"
|
|
@@ -279,7 +279,7 @@ grammar Blocktalk do
|
|
|
279
279
|
first_pair = first_entry.value
|
|
280
280
|
hash_str += "#{first_pair[0]} => #{first_pair[1]},"
|
|
281
281
|
rest_pairs.elements.each do |ws_and_pair|
|
|
282
|
-
pair = ws_and_pair.pair
|
|
282
|
+
pair = ws_and_pair.pair.value
|
|
283
283
|
hash_str += "#{pair[0]} => #{pair[1]},"
|
|
284
284
|
end
|
|
285
285
|
hash_str += "}"
|
data/lib/blocktalk.bt
CHANGED
data/lib/kernel/codeblock.rb
CHANGED
|
@@ -50,8 +50,22 @@ module Kernel
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def until(&
|
|
54
|
-
|
|
53
|
+
def until(&condition_block)
|
|
54
|
+
while not condition_block.call
|
|
55
|
+
self.call
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def if(condition)
|
|
60
|
+
if condition
|
|
61
|
+
self.call
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def unless(condition)
|
|
66
|
+
unless condition
|
|
67
|
+
self.call
|
|
68
|
+
end
|
|
55
69
|
end
|
|
56
70
|
end
|
|
57
71
|
end
|
data/parser/nodes/string.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Blocktalk
|
|
2
2
|
class StringLiteralNode < Treetop::Runtime::SyntaxNode
|
|
3
3
|
def value
|
|
4
|
-
"\"" + self.string_val.elements.collect{|e| e.value}.join("") + "\""
|
|
4
|
+
"\"" + self.string_val.elements.collect{|e| e.value}.join("").gsub('"', '\"').gsub("'", "\'") + "\""
|
|
5
5
|
end
|
|
6
6
|
end
|
|
7
7
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bakkdoor-blocktalk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Christopher Bertels
|
|
@@ -36,7 +36,6 @@ files:
|
|
|
36
36
|
- TODO
|
|
37
37
|
- LICENSE
|
|
38
38
|
- evaluator.rb
|
|
39
|
-
- version.rb
|
|
40
39
|
- grammar/blocktalk.tt
|
|
41
40
|
- grammar/blocktalk.rb
|
|
42
41
|
- lib/core.rb
|
|
@@ -51,21 +50,25 @@ files:
|
|
|
51
50
|
- lib/kernel/system.rb
|
|
52
51
|
- lib/kernel/object.rb
|
|
53
52
|
- lib/blocktalk
|
|
53
|
+
- lib/blocktalk/hash.bt
|
|
54
54
|
- lib/blocktalk/string.bt
|
|
55
55
|
- lib/blocktalk/array.bt
|
|
56
56
|
- lib/blocktalk.bt
|
|
57
57
|
- bin/blocktalk
|
|
58
|
+
- examples/webserver.bt
|
|
58
59
|
- examples/test3.bt
|
|
59
60
|
- examples/fac.bt
|
|
60
61
|
- examples/chained_method_call.bt
|
|
61
62
|
- examples/exceptions.bt
|
|
62
63
|
- examples/string_interpol.bt
|
|
63
64
|
- examples/test2.bt
|
|
65
|
+
- examples/literals.bt
|
|
64
66
|
- examples/ruby_methods.bt
|
|
65
67
|
- examples/multiple_methodcall.bt
|
|
66
68
|
- examples/linecounter.bt
|
|
67
69
|
- examples/require.bt
|
|
68
70
|
- examples/portscan.bt
|
|
71
|
+
- examples/conditionals.bt
|
|
69
72
|
- examples/classes_modules.bt
|
|
70
73
|
- examples/test.bt
|
|
71
74
|
- examples/string_test.bt
|
data/version.rb
DELETED