story-gen 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +2 -0
- data/README.md +30 -5
- data/bin/story +5 -0
- data/lib/story/compile.rb +33 -9
- data/lib/story/samples_dir.rb +6 -0
- data/sample/fight_club.sdl +21 -24
- data/sample/university.sdl +6 -5
- data/sample//320/261/320/276/320/271/321/206/320/276/320/262/321/201/320/272/320/270/320/271_/320/272/320/273/321/203/320/261.sdl +20 -23
- data/sample//321/203/320/275/320/270/320/262/320/265/321/200/321/201/320/270/321/202/320/265/321/202.sdl +6 -5
- metadata +4 -3
- data/gem.gemspec +0 -13
data/.yardopts
ADDED
data/README.md
CHANGED
@@ -30,7 +30,12 @@ A simple story:
|
|
30
30
|
|
31
31
|
"Hello, world!"
|
32
32
|
|
33
|
-
It just prints "Hello, world!".
|
33
|
+
It just prints "Hello, world!". To print newline just write `newline` or `nl`:
|
34
|
+
|
35
|
+
"Hello, world!" newline
|
36
|
+
"Another line of helloness!" nl
|
37
|
+
|
38
|
+
Or you may insert newline inside the quotes:
|
34
39
|
|
35
40
|
"
|
36
41
|
Chapter I
|
@@ -50,7 +55,7 @@ A story is based on Facts. To state a Fact just write it:
|
|
50
55
|
|
51
56
|
"John" loves "Liza"
|
52
57
|
|
53
|
-
In the Fact expression you may use english and russian words (except keywords, see below), characters from "
|
58
|
+
In the Fact expression you may use english and russian words (except keywords, see below), characters from "#№@$%/-", integer numbers (e.g., `18`) and arbitrary double- or single-quoted strings (`"..."` or `'...'`). Trailing commas are ignored (`xxx yyy zzz,` is the same as `xxx yyy zzz`). The words are case-insensitive (so `loves` and `Loves` mean the same), quoted strings are case-sensitive (so `"John"`≠`"JOHN"`).
|
54
59
|
|
55
60
|
Let's state some Facts:
|
56
61
|
|
@@ -78,9 +83,9 @@ Here `X` is a variable. Variable names consist of underscores ("_") and capital
|
|
78
83
|
|
79
84
|
You may use the captured variables in the statement after `then` keyword.
|
80
85
|
|
81
|
-
To print the captured variable you just write it along with some quoted
|
86
|
+
To print the captured variable you just write it along with some quoted strings and newlines:
|
82
87
|
|
83
|
-
"Let's meet " X;
|
88
|
+
"Let's meet " X "." nl;
|
84
89
|
|
85
90
|
But wait... We have two boys! What does `if` choose as `X` then? The answer is: random. If there are several combinations of variables which fit the condition then a random combination is chosen.
|
86
91
|
|
@@ -134,6 +139,16 @@ Or combine `if`-s with some statement:
|
|
134
139
|
|
135
140
|
This is like a classical `if ... else if ... else ...` but if multiple conditions are true then random one is chosen (instead of the first one, like in the classical `if-else`). The last `or` is the same as `else` in the classical `if-else` - it is chosen if all conditions are false.
|
136
141
|
|
142
|
+
The full form of `if`:
|
143
|
+
|
144
|
+
If <condition> [,] then <statement> [,]
|
145
|
+
or if <condition> [,] then <statement> [,]
|
146
|
+
or if <condition> [,] then <statement> [,]
|
147
|
+
...
|
148
|
+
or <statement>
|
149
|
+
|
150
|
+
Here `[,]` means "optional comma".
|
151
|
+
|
137
152
|
You may use captured variables to state a Fact:
|
138
153
|
|
139
154
|
If X is a boy and Y is a girl then
|
@@ -148,7 +163,13 @@ Set multiple Facts false:
|
|
148
163
|
|
149
164
|
If X is a boy then
|
150
165
|
X not loves *
|
151
|
-
|
166
|
+
|
167
|
+
You may use the captured variables in another conditions (by prefixing them with hat "^"):
|
168
|
+
|
169
|
+
If X is a boy then
|
170
|
+
if ^X loves * then "We found "X" which is in love!"
|
171
|
+
or "We found "X" which is stll single."
|
172
|
+
|
152
173
|
To combine several statements into one use a colon (":") with the final dot ("."):
|
153
174
|
|
154
175
|
If X is a boy then:
|
@@ -257,3 +278,7 @@ Examples
|
|
257
278
|
--------
|
258
279
|
|
259
280
|
See them in "sample" directory!
|
281
|
+
|
282
|
+
You may find the "sample" directory with
|
283
|
+
|
284
|
+
story --samples
|
data/bin/story
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'story/compile'
|
3
3
|
require 'optparse'
|
4
|
+
require 'story/samples_dir'
|
4
5
|
|
5
6
|
$output_file = nil
|
6
7
|
$input_file = nil
|
@@ -40,6 +41,10 @@ OptionParser.new do |opts|
|
|
40
41
|
story.relations.each { |relation| output.puts relation }
|
41
42
|
end
|
42
43
|
end
|
44
|
+
opts.on "--samples", "Show directory with samples and exit" do
|
45
|
+
puts Story::SAMPLES_DIR
|
46
|
+
exit
|
47
|
+
end
|
43
48
|
opts.on "-h", "--help", "Show this message and exit" do
|
44
49
|
puts opts
|
45
50
|
exit
|
data/lib/story/compile.rb
CHANGED
@@ -158,6 +158,8 @@ class Story
|
|
158
158
|
|
159
159
|
end
|
160
160
|
|
161
|
+
Above = ASTNode.new :var
|
162
|
+
|
161
163
|
Asterisk = ASTNode.new
|
162
164
|
|
163
165
|
# @!visibility private
|
@@ -173,6 +175,7 @@ class Story
|
|
173
175
|
case part
|
174
176
|
when String then part.to_rb
|
175
177
|
when Var then at(part.pos) { part.name }
|
178
|
+
when Above[Var] then at(part.pos) { part.var.name }
|
176
179
|
end <<
|
177
180
|
")"
|
178
181
|
end.join_code("\n") << "\n" <<
|
@@ -197,6 +200,8 @@ class Story
|
|
197
200
|
nil
|
198
201
|
when Var then
|
199
202
|
"#{at(arg.pos) { arg.name }} == #{var_arg_valuess}[#{i}]"
|
203
|
+
when Above[Var] then
|
204
|
+
"#{at(arg.pos) { arg.var.name }} == #{var_arg_valuess}[#{i}]"
|
200
205
|
else
|
201
206
|
"#{arg.to_rb} == #{var_arg_valuess}[#{i}]"
|
202
207
|
end
|
@@ -222,6 +227,8 @@ class Story
|
|
222
227
|
raise Parse::Error.new(arg.pos, "not supported")
|
223
228
|
when Var then
|
224
229
|
at(arg.pos) { arg.name }
|
230
|
+
when Above[Var] then
|
231
|
+
at(arg.pos) { arg.var.name }
|
225
232
|
else
|
226
233
|
arg.to_rb
|
227
234
|
end
|
@@ -311,9 +318,14 @@ class Story
|
|
311
318
|
private
|
312
319
|
|
313
320
|
def to_code_(range_part)
|
321
|
+
to_code = lambda do |var, pos|
|
322
|
+
at(pos) { code << "(must_be(" << var.name << ", Integer); " << var.name << ")" }
|
323
|
+
end
|
324
|
+
#
|
314
325
|
case range_part
|
315
326
|
when Integer then range_part.to_rb
|
316
|
-
when Var then
|
327
|
+
when Var then to_code.(range_part, range_part.pos)
|
328
|
+
when Above[Var] then to_code.(range_part.var, range_part.pos)
|
317
329
|
else raise Parse::Error.new(pos, "what?")
|
318
330
|
end
|
319
331
|
end
|
@@ -401,6 +413,8 @@ class Story
|
|
401
413
|
map << "#{var_arg_valuess}[#{i}]"
|
402
414
|
known_var_index[var] = i
|
403
415
|
end
|
416
|
+
when Above[Var] then
|
417
|
+
select << "#{at(arg.pos) { arg.var.name }} == #{var_arg_valuess}[#{i}]"
|
404
418
|
else
|
405
419
|
select << "#{arg.to_rb} == #{var_arg_valuess}[#{i}]"
|
406
420
|
end
|
@@ -485,6 +499,7 @@ class Story
|
|
485
499
|
to_code = lambda do |operand|
|
486
500
|
case operand
|
487
501
|
when Var then "#{var_arg_valuess}[#{e1.var_args_indexes[operand]}]"
|
502
|
+
when Above[Var] then at(operand.pos) { operand.var.name }
|
488
503
|
else operand.to_rb
|
489
504
|
end
|
490
505
|
end
|
@@ -605,7 +620,7 @@ class Story
|
|
605
620
|
|
606
621
|
rule :statement_tell do
|
607
622
|
parts = many1 {
|
608
|
-
_{ string } or _{ var }
|
623
|
+
_{ string } or _{ newline } or _{ var }
|
609
624
|
} and
|
610
625
|
_(Statement::Tell[parts])
|
611
626
|
end
|
@@ -619,7 +634,7 @@ class Story
|
|
619
634
|
_if_ and c = fact_expr and opt { comma } and _then_ and s = statement and [c, s]
|
620
635
|
}
|
621
636
|
or_delimiter = lambda {
|
622
|
-
opt {
|
637
|
+
opt { comma } and _or_
|
623
638
|
}
|
624
639
|
#
|
625
640
|
c_and_s1 = if_then.() and
|
@@ -727,6 +742,7 @@ class Story
|
|
727
742
|
_{ _not_ and act { negated = !negated } } or
|
728
743
|
_{ v = value and act { args << v; relation_id << :* } } or
|
729
744
|
_{ v = var and act { args << v; relation_id << :* } } or
|
745
|
+
_{ v = above_var and act { args << v; relation_id << :* } } or
|
730
746
|
_{ w = word and act { relation_id << w.ru_downcase } }
|
731
747
|
} and
|
732
748
|
# act { relation_id.chomp!(",") } and
|
@@ -784,8 +800,8 @@ class Story
|
|
784
800
|
scan("*") and _(Asterisk.new)
|
785
801
|
end
|
786
802
|
|
787
|
-
token :other_char, "any of
|
788
|
-
scan(/[
|
803
|
+
token :other_char, "any of `#№@$%/'" do
|
804
|
+
scan(/[\#\№\@\$\%\/]/)
|
789
805
|
end
|
790
806
|
|
791
807
|
token :_for_, "`for'" do
|
@@ -824,6 +840,10 @@ class Story
|
|
824
840
|
t = word_ and /^(times|раза?)$/ === t
|
825
841
|
end
|
826
842
|
|
843
|
+
token :newline, "`newline'" do
|
844
|
+
t = word_ and /^(newline|nl)$/ === t and "\n"
|
845
|
+
end
|
846
|
+
|
827
847
|
token :number, "number" do
|
828
848
|
n = scan(/\d+/) and n.to_i
|
829
849
|
end
|
@@ -855,10 +875,14 @@ class Story
|
|
855
875
|
_(Var[n.ru_downcase, n])
|
856
876
|
end
|
857
877
|
|
878
|
+
token :above_var, "^variable" do
|
879
|
+
scan("^") and v = var and _(Above[v])
|
880
|
+
end
|
881
|
+
|
858
882
|
token :word, "word" do
|
859
883
|
not_follows(
|
860
884
|
:_not_, :_and_, :_or_, :_if_, :_then_, :var, :_while_, :_for_, :all,
|
861
|
-
:times
|
885
|
+
:times, :newline
|
862
886
|
) and
|
863
887
|
word_
|
864
888
|
end
|
@@ -913,11 +937,11 @@ class Story
|
|
913
937
|
end
|
914
938
|
|
915
939
|
# begin
|
916
|
-
#
|
940
|
+
# eval(Story.compile(<<-STORY)).new.write
|
917
941
|
#
|
918
|
-
#
|
942
|
+
# "Hello, world!" newline
|
919
943
|
# Either "John" loves "Liza",
|
920
|
-
# or ("Hello, world, again!"; "John" kisses "Liza";).
|
944
|
+
# or ("Hello, world, again!" nl; "John" kisses "Liza";).
|
921
945
|
# STORY
|
922
946
|
# rescue Parse::Error => e
|
923
947
|
# puts "error: #{e.pos.file}:#{e.pos.line}:#{e.pos.column}: #{e.message}"
|
data/sample/fight_club.sdl
CHANGED
@@ -10,49 +10,46 @@ require 'unique_names'
|
|
10
10
|
names = UniqueNames.english_male
|
11
11
|
```
|
12
12
|
|
13
|
-
"Today in the fight club the tournament is being held! Meet the participants:"
|
13
|
+
"Today in the fight club the tournament is being held! Meet the participants:" nl;
|
14
14
|
|
15
|
-
10
|
15
|
+
10 times:
|
16
16
|
```n = names.pop```;
|
17
|
-
N is the current participant;
|
18
17
|
N is in;
|
19
|
-
"
|
20
|
-
|
21
|
-
either "tiger", or "fox", or "bear", or ("horse"; N has hooves);
|
18
|
+
"- "N", the ";
|
19
|
+
either "tiger", or "fox", or "bear", or ("horse"; N has hooves);
|
22
20
|
" ";
|
23
21
|
either ("with powerful hands"; N uses "hands"),
|
24
22
|
or ("with powerful feet"; N uses "feet"),
|
25
23
|
or:
|
26
|
-
if
|
27
|
-
"with powerful hooves";
|
24
|
+
if ^N has hooves then (
|
25
|
+
"with powerful hooves"; N uses "hooves"
|
28
26
|
)
|
29
27
|
or (
|
30
28
|
"with sharp claws"; N uses "claws"
|
31
29
|
)
|
32
30
|
.
|
33
|
-
|
31
|
+
nl;
|
34
32
|
.
|
35
|
-
"
|
36
33
|
|
37
|
-
|
34
|
+
nl
|
35
|
+
"Let the tournament begin!" nl
|
36
|
+
nl
|
38
37
|
|
39
|
-
"
|
40
38
|
While the tournament not complete:
|
41
39
|
If X is in and Y is in and X != Y, then:
|
42
40
|
(note: fight!)
|
43
41
|
either (X won; Y lost), or (Y won; X lost);
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
42
|
+
if A won and B lost then:
|
43
|
+
if ^A uses "hands" then ""A" has beaten "B". "
|
44
|
+
or if ^A uses "feet" then ""A" has kicked "B". "
|
45
|
+
or if ^A uses "hooves" then ""A" has kicked "B" and knocked him out. "
|
46
|
+
or if ^A uses "claws" then ""A" has scratched the whole "B". ";
|
47
|
+
A not won; B not lost;
|
48
|
+
B is not in;
|
49
|
+
.
|
52
50
|
.
|
53
51
|
Or the tournament complete;
|
54
52
|
.
|
55
|
-
If X is in then ""X" is the winner!"
|
56
|
-
|
57
|
-
|
58
|
-
"
|
53
|
+
If X is in then ""X" is the winner!"
|
54
|
+
nl
|
55
|
+
nl
|
data/sample/university.sdl
CHANGED
@@ -41,13 +41,14 @@ While X is a boy and X not loves *:
|
|
41
41
|
either
|
42
42
|
"After the lectures they went home and did their home tasks. "
|
43
43
|
or:
|
44
|
-
"After the lectures "X" caught "Y" and told her that he loves her! "
|
44
|
+
"After the lectures "X" caught "Y" and told her that he loves her! ";
|
45
45
|
X loves Y.
|
46
46
|
.
|
47
47
|
.
|
48
48
|
.
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
Then they all lived long and happy!
|
53
|
-
|
50
|
+
nl
|
51
|
+
nl
|
52
|
+
"Then they all lived long and happy!"
|
53
|
+
nl
|
54
|
+
nl
|
@@ -10,49 +10,46 @@ require 'unique_names'
|
|
10
10
|
names = UniqueNames.russian_male
|
11
11
|
```
|
12
12
|
|
13
|
-
"Сегодня в бойцовском клубе проводится турнир! Поприветствуйте участников:"
|
13
|
+
"Сегодня в бойцовском клубе проводится турнир! Поприветствуйте участников:" nl;
|
14
14
|
|
15
15
|
10 раз:
|
16
16
|
```n = names.pop```;
|
17
|
-
N - текущий участник;
|
18
17
|
N участвует в турнире;
|
19
|
-
"
|
20
|
-
- "N", ";
|
18
|
+
"- "N", ";
|
21
19
|
либо "тигр", либо "лис", либо "медведь", либо ("конь"; N имеет копыта);
|
22
|
-
" ";
|
20
|
+
" " ;
|
23
21
|
либо ("с сильными руками"; N использует "руки"),
|
24
22
|
либо ("с сильными ногами"; N использует "ноги"),
|
25
23
|
либо:
|
26
|
-
если
|
27
|
-
"с мощными копытами";
|
24
|
+
если ^N имеет копыта, то (
|
25
|
+
"с мощными копытами"; N использует "копыта"
|
28
26
|
)
|
29
27
|
или (
|
30
28
|
"с острыми когтями"; N использует "когти"
|
31
29
|
)
|
32
30
|
.
|
33
|
-
|
31
|
+
nl;
|
34
32
|
.
|
35
|
-
"
|
36
33
|
|
37
|
-
|
34
|
+
nl
|
35
|
+
"Да начнется турнир!" nl
|
36
|
+
nl
|
38
37
|
|
39
|
-
"
|
40
38
|
Пока не конец турнира:
|
41
39
|
Если X участвует в турнире и Y участвует в турнире и X != Y, то:
|
42
40
|
(note: бой!)
|
43
41
|
либо (X победил; Y проиграл), либо (Y победил; X проиграл);
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
42
|
+
если A победил и B проиграл, то:
|
43
|
+
если ^A использует "руки", то ""A" избил "B". "
|
44
|
+
или если ^A использует "ноги", то ""A" запинал "B". "
|
45
|
+
или если ^A использует "копыта", то ""A" лягнул "B" и вырубил его. "
|
46
|
+
или если ^A использует "когти", то ""A" исцарапал всего "B". ";
|
47
|
+
A не победил; B не проиграл;
|
48
|
+
A не участвует в турнире;
|
49
|
+
.
|
52
50
|
.
|
53
51
|
Или конец турнира;
|
54
52
|
.
|
55
|
-
Если X участвует в турнире, то ""X" - победитель!"
|
56
|
-
|
57
|
-
|
58
|
-
"
|
53
|
+
Если X участвует в турнире, то ""X" - победитель!"
|
54
|
+
nl
|
55
|
+
nl
|
@@ -42,13 +42,14 @@
|
|
42
42
|
либо
|
43
43
|
"После лекций они пошли домой и делали уроки. "
|
44
44
|
либо:
|
45
|
-
"После лекций "X" поймал "Y" и сказал ей, что любит её! "
|
45
|
+
"После лекций "X" поймал "Y" и сказал ей, что любит её! ";
|
46
46
|
X любит Y.
|
47
47
|
.
|
48
48
|
.
|
49
49
|
.
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
И жили они долго и счастливо!
|
54
|
-
|
51
|
+
nl
|
52
|
+
nl
|
53
|
+
"И жили они долго и счастливо!"
|
54
|
+
nl
|
55
|
+
nl
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: story-gen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-01-
|
12
|
+
date: 2016-01-30 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Generate stories from descriptions based on Facts!
|
15
15
|
email: various.furriness@gmail.com
|
@@ -22,6 +22,7 @@ files:
|
|
22
22
|
- lib/any.rb
|
23
23
|
- lib/fact.rb
|
24
24
|
- lib/story/compile.rb
|
25
|
+
- lib/story/samples_dir.rb
|
25
26
|
- lib/array/case_equal_fixed.rb
|
26
27
|
- lib/array/separate.rb
|
27
28
|
- lib/array/to_h.rb
|
@@ -40,7 +41,7 @@ files:
|
|
40
41
|
- lib/object/map_.rb
|
41
42
|
- lib/object/to_rb.rb
|
42
43
|
- README.md
|
43
|
-
-
|
44
|
+
- .yardopts
|
44
45
|
- sample/fight_club.sdl
|
45
46
|
- sample/университет.sdl
|
46
47
|
- sample/бойцовский_клуб.sdl
|
data/gem.gemspec
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
|
2
|
-
Gem::Specification.new do |s|
|
3
|
-
s.name = 'story-gen'
|
4
|
-
s.version = '0.0.1'
|
5
|
-
s.date = '2016-01-10'
|
6
|
-
s.summary = "Story generator"
|
7
|
-
s.description = "Generate stories from descriptions based on Facts!"
|
8
|
-
s.authors = ["Various Furriness"]
|
9
|
-
s.email = 'various.furriness@gmail.com'
|
10
|
-
s.files = Dir["lib/**/*.rb"] + ["README.md", "gem.gemspec"] + Dir["sample/*"]
|
11
|
-
s.executables = Dir["bin/*"].map { |f| File.basename(f) }
|
12
|
-
s.license = 'MIT'
|
13
|
-
end
|