-
Notifications
You must be signed in to change notification settings - Fork 2
/
sbn.reb
168 lines (153 loc) · 3.51 KB
/
sbn.reb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
Rebol [
title: "A SBN Language Compiler"
date: 7-May-2017
file: %sbn.reb
author: "Wayne Cui"
version: 0.0.2
info: "inspired by https://github.com/kosamari/sbn"
]
lexer: function [code][
tokens: split code charset [" ^/"]
token-blk: copy []
foreach token tokens [
either error? result: try [ to integer! token ] [
repend/only token-blk ['type 'word 'value to lit-word! token]
][
repend/only token-blk ['type 'number 'value to integer! token]
]
]
token-blk
]
parser: function [tokens][
AST: [type "Drawing" body []]
while [(length? tokens) > 0] [
current-token: take tokens
if current-token/type = 'word [
switch current-token/value [
'Paper [
expression: [
'type 'CallExpression
'name 'Paper
'arguments []
]
argument: take tokens
;probe argument/type
either argument/type = 'number [
repend/only expression/arguments ['type 'NumberLiteral 'value argument/value]
repend/only AST/body expression
][
throw "Paper command must be followed by a number."
]
]
'Pen [
expression: [
'type 'CallExpression
'name 'Pen
'arguments []
]
argument: take tokens
either argument/type = 'number [
repend/only expression/arguments ['type 'NumberLiteral 'value argument/value]
repend/only AST/body expression
][
throw "Pen command must be followed by a number."
]
]
'Line [
expression: [
'type 'CallExpression
'name 'Line
'arguments (copy [])
]
arguments: copy []
loop 4 [
argument: take tokens
either argument/type = 'number [
repend/only arguments ['type 'NumberLiteral 'value argument/value]
expression/arguments: arguments
][
throw "Line command must be followed by a number."
]
]
;probe expression
repend/only AST/body expression
]
]
]
]
AST
]
transformer: function[ ast ][
svg-ast: [
'tag 'svg
'attr [
'width 100
'height 100
'viewBox [0 0 100 100]
'xmlns http://www.w3.org/2000/svg
'version "1.1"
]
'body []
]
pen-color: 100
while [(length? ast/body) > 0][
node: take ast/body
switch node/name [
Paper [
paper-color: 100 - node/arguments/1/value
repend/only svg-ast/body [
'tag 'rect
'attr reduce [
'x 0
'y 0
'width 100
'height 100
'fill rejoin ["rgb(" paper-color "%," paper-color "%," paper-color "%)"]
]
]
]
Pen [
pen-color: 100 - node/arguments/1/value
]
Line [
repend/only svg-ast/body [
'tag 'line
'attr reduce[
'x1 node/arguments/1/value
'y1 node/arguments/2/value
'x2 node/arguments/3/value
'y2 node/arguments/4/value
'stroke-linecap 'round
'stroke (rejoin ["rgb(" pen-color "%," pen-color "%," pen-color "%)"])
]
]
]
]
]
svg-ast
]
generator: function[svg-ast][
svg-attr: create-attr-string svg-ast/attr
;probe svg-attr
elements: copy []
foreach node svg-ast/body [
append elements rejoin ["<" node/tag space create-attr-string node/attr {></} node/tag {>} lf]
]
return rejoin [{<svg } svg-attr {>^/} elements {^/</svg>}]
]
create-attr-string: function[attr][
result: copy []
foreach [key value] attr [
append result rejoin [key {="} value {"} space ]
]
return result
]
compile: function[code][
write %simple.svg generator transformer parser lexer code
]
code: {Paper 100 Pen 0
Line 50 15 85 80
Line 85 80 15 80
Line 15 80 50 15}
;probe generator transformer parser lexer code
compile code