story-gen 0.0.1 → 0.0.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/.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
|