Show More
@@ -0,0 +1,17 b'' | |||
|
1 | ||
|
2 | all: diagrams.png $(BIN) | |
|
3 | ||
|
4 | $(BIN): src/*.lisp src/*.ps | |
|
5 | buildapp.sbcl | |
|
6 | ||
|
7 | install-deps: | |
|
8 | sbcl --load install-deps.lisp | |
|
9 | ||
|
10 | update-deps: | |
|
11 | sbcl --load update-deps.lisp | |
|
12 | ||
|
13 | diagrams.png: diagrams.dot | |
|
14 | dot $< -T png -o $@ | |
|
15 | ||
|
16 | clean: | |
|
17 | rm sugar-qsp |
@@ -0,0 +1,9 b'' | |||
|
1 | ||
|
2 | * API | |
|
3 | * Sample | |
|
4 | * html | |
|
5 | * bundle it all | |
|
6 | * Qlot | |
|
7 | * make a binary | |
|
8 | ||
|
9 | * Finish intrinsics and api No newline at end of file |
@@ -0,0 +1,18 b'' | |||
|
1 | ||
|
2 | digraph diagrams { | |
|
3 | rankdir = LR | |
|
4 | subgraph cluster_code { | |
|
5 | label = "Code Transformations" | |
|
6 | QSP -> intermediate [label="parser.lisp (esrap)"] | |
|
7 | intermediate -> Parenscript [label="ps-macros.lisp"] | |
|
8 | Parenscript -> Javascript [label="main.lisp"] | |
|
9 | } | |
|
10 | subgraph cluster_js { | |
|
11 | label = "Javascript modules call hierarchy" | |
|
12 | user -> "ps-macros" | |
|
13 | user -> intrinsics | |
|
14 | "ps-macros" -> intrinsics | |
|
15 | "ps-macros" -> api | |
|
16 | intrinsics -> api | |
|
17 | } | |
|
18 | } |
|
1 | NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,22 b'' | |||
|
1 | ||
|
2 | # dynamic | |
|
3 | DYNAMIC {$a=0} | |
|
4 | DYNAMIC {if $a="string":'text!'} | |
|
5 | DYNAMIC { | |
|
6 | $args[0] | |
|
7 | addobj $args[1] | |
|
8 | },'Текст','Вилка' | |
|
9 | ||
|
10 | DYNEVAL({result = 3+4}) | |
|
11 | PL DYNEVAL({$result = mid("abcd",2,1)+"qwerty"}) | |
|
12 | PL DYNEVAL({$test + $args[0]}, val($test)) | |
|
13 | проход=DYNEVAL({result = ($args[0] <> 'текст')}, 'строка') | |
|
14 | ||
|
15 | $code = { | |
|
16 | *pl "<<$args[0]>>" | |
|
17 | *pl $args[0] | |
|
18 | } | |
|
19 | ||
|
20 | DYNAMIC $code,'asdfg' | |
|
21 | ! будет выведено две строки 'asdfg' | |
|
22 | - |
@@ -0,0 +1,18 b'' | |||
|
1 | ||
|
2 | # diag | |
|
3 | ! простой вывод сообщения. | |
|
4 | MSG 'Много спелых груш' | |
|
5 | ! получим окно с сообщением 'Много спелых груш' | |
|
6 | ||
|
7 | ! Пример сообщения в действии ACT. | |
|
8 | ACT 'Поесть груш': | |
|
9 | MSG 'Ммм груши очень вкусные' | |
|
10 | END | |
|
11 | ! Получим вывод сообщения при клике по действию "Поесть груш" | |
|
12 | ||
|
13 | !Пример с условием. | |
|
14 | IF $hlebgotov = 1: | |
|
15 | MSG 'Похоже хлеб уже готов' | |
|
16 | END | |
|
17 | ! Получаем вывод сообщения когда условие $hlebgotov = 1 | |
|
18 | - |
@@ -0,0 +1,21 b'' | |||
|
1 | ||
|
2 | # objs | |
|
3 | OBJECTS['деньги'] = 12 | |
|
4 | OBJECTS['патроны'] = 137 | |
|
5 | ||
|
6 | 'Количество: <<OBJECTS[$getobj(countobj)]>>' | |
|
7 | ||
|
8 | !Первый предмет в списке | |
|
9 | GETOBJ(1) | |
|
10 | ||
|
11 | !Последний предмет в списке | |
|
12 | GETOBJ(COUNTOBJ) | |
|
13 | ||
|
14 | i = 1 | |
|
15 | :loop | |
|
16 | IF i <= COUNTOBJ: | |
|
17 | OBJECTS[$GETOBJ(i)] = OBJECTS[$GETOBJ(i)] + 1 | |
|
18 | i = i + 1 | |
|
19 | JUMP 'loop' | |
|
20 | END | |
|
21 | - |
@@ -0,0 +1,13 b'' | |||
|
1 | ||
|
2 | # menu | |
|
3 | ! нет иконки | |
|
4 | $usr_menu[0] = 'Взять предмет:take_item' | |
|
5 | ! иконка задана gif-файлом | |
|
6 | $usr_menu[1] = 'Положить предмет:put_item:images/put_item.gif' | |
|
7 | ! иконка задана значением $icon_file | |
|
8 | $usr_menu[2] = 'Осмотреть предмет:look_item:<<$icon_file>>' | |
|
9 | ! пункт меню задан 3-мя переменными | |
|
10 | $usr_menu[3] = '<<$name>>:<<$loc>>:<<$file>>' | |
|
11 | ||
|
12 | menu 'usr_menu' &! покажет меню из 4-х пунктов | |
|
13 | - |
@@ -0,0 +1,15 b'' | |||
|
1 | ||
|
2 | # sound | |
|
3 | !Громкость 100% | |
|
4 | PLAY 'sound/music.mp3' | |
|
5 | !Громкость 50% | |
|
6 | PLAY 'sound/music.mp3',50 | |
|
7 | !Громкость 0% (без звука) | |
|
8 | PLAY 'sound/music.mp3',0 | |
|
9 | ||
|
10 | !Проигрывание файла по адресу из переменной $file | |
|
11 | ! с расширением 'mid' | |
|
12 | ! и громкостью volume | |
|
13 | PLAY '<<$file>>.mid',volume | |
|
14 | PLAY $file,volume &! аналогично | |
|
15 | - |
@@ -0,0 +1,14 b'' | |||
|
1 | ||
|
2 | # img | |
|
3 | $BACKIMAGE = 'content/back.png' | |
|
4 | ||
|
5 | VIEW 'content/monster.png' | |
|
6 | ||
|
7 | ! Включаем режим HTML. Если во всей игре используется HTML, | |
|
8 | ! то достаточно включить его на самой первой локации. | |
|
9 | USEHTML = 1 | |
|
10 | ! Выводим картинку в основное описание | |
|
11 | '<img src="content/room.jpg">' | |
|
12 | ! Выводим картинку в доп. описание | |
|
13 | PL '<img src="content/map.jpg">' | |
|
14 | - |
@@ -0,0 +1,20 b'' | |||
|
1 | ||
|
2 | # input | |
|
3 | $text = $USER_TEXT | |
|
4 | CMDCLEAR | |
|
5 | SHOWINPUT 0 | |
|
6 | ||
|
7 | $name = INPUT('Как звать тебя, герой?') | |
|
8 | ||
|
9 | ! Вопрос с одним правильным ответом. | |
|
10 | if input ('Что приходит после тьмы?') = 'свет': | |
|
11 | msg 'Все верно.' | |
|
12 | else | |
|
13 | msg 'Ответ не верный.' | |
|
14 | end | |
|
15 | ||
|
16 | ! Пример реализации вопроса с несколькими вариантами ответа из которых любой будет правильным. | |
|
17 | $answer = TRIM(LCASE(input('Ответить'))) | |
|
18 | if INSTR($answer, 'красный') OR INSTR($answer, 'желтый') OR INSTR($answer, 'зеленый'): gt 'win' | |
|
19 | ! Введя красный или зеленый ил желтый произойдет переход на локацию 'win' | |
|
20 | - |
@@ -0,0 +1,44 b'' | |||
|
1 | ||
|
2 | # time | |
|
3 | ! устанавливает период выполнения кода | |
|
4 | ! на локации-счётчике в 100 миллисекунд | |
|
5 | SETTIMER 100 | |
|
6 | ||
|
7 | settimer 20 | |
|
8 | if стихотворение=0: | |
|
9 | if время_первая_строка=0: | |
|
10 | время_первая_строка=msecscount+1500 | |
|
11 | end | |
|
12 | if msecscount>=время_первая_строка: | |
|
13 | *pl 'Веленью совести, о Муза, будь послушна!' | |
|
14 | стихотворение=1 | |
|
15 | end | |
|
16 | end | |
|
17 | if стихотворение=1: | |
|
18 | if время_вторая_строка=0: | |
|
19 | время_вторая_строка=msecscount+1500 | |
|
20 | end | |
|
21 | if msecscount>=время_вторая_строка: | |
|
22 | *pl 'Обиды не страшась, не требуя венца,' | |
|
23 | стихотворение=2 | |
|
24 | end | |
|
25 | end | |
|
26 | if стихотворение=2: | |
|
27 | if время_третья_строка=0: | |
|
28 | время_третья_строка=msecscount+1500 | |
|
29 | end | |
|
30 | if msecscount>=время_третья_строка: | |
|
31 | *pl 'Хвалу и клевету приемли равнодушно' | |
|
32 | стихотворение=3 | |
|
33 | end | |
|
34 | end | |
|
35 | if стихотворение=3: | |
|
36 | if время_четвёртая_строка=0: | |
|
37 | время_четвёртая_строка=msecscount+1500 | |
|
38 | end | |
|
39 | if msecscount>=время_четвёртая_строка: | |
|
40 | *pl 'И не оспаривай глупца.' | |
|
41 | стихотворение=4 | |
|
42 | end | |
|
43 | end | |
|
44 | - |
@@ -0,0 +1,16 b'' | |||
|
1 | ||
|
2 | # expr | |
|
3 | x=5 | |
|
4 | y=6 | |
|
5 | tmp=(x ! y) OR (x <> y) | |
|
6 | tmp=x OR y | |
|
7 | tmp=x AND y | |
|
8 | tmp=y MOD x | |
|
9 | tmp=OBJ 'стул' | |
|
10 | tmp=LOC 'дом' | |
|
11 | tmp=res = x*y + y*-x/2 | |
|
12 | tmp=res = NO x = y | |
|
13 | ||
|
14 | tmp=15*5/2 | |
|
15 | tmp=15/2*5 | |
|
16 | - |
@@ -0,0 +1,56 b'' | |||
|
1 | ||
|
2 | # code | |
|
3 | яблоко = 1 | |
|
4 | груша = 1 | |
|
5 | ||
|
6 | *pl 'Яблок' + яблоко | |
|
7 | *pl 'Груш' + груша | |
|
8 | ||
|
9 | '<a href="EXEC: яблоко += 1 & GT $CURLOC">яблоко</a>' | |
|
10 | !При нажатии на ссылку выполнится код: | |
|
11 | яблоко += 1 | |
|
12 | GT $CURLOC | |
|
13 | ||
|
14 | !Однострочный комментарий | |
|
15 | яблоки = 0 | |
|
16 | !'Многострочный | |
|
17 | комментарий' | |
|
18 | яблоки = 1 | |
|
19 | сыр = 5 & ! А здесь"комментарий начинается | |
|
20 | в той же строке, но" заканчивается 'сильно | |
|
21 | позже'. Во всём виноваты {кавычки и скобки | |
|
22 | }Кстати: | |
|
23 | яблоки=0 | |
|
24 | !'Комментарии рекомендуется писать всё-таки | |
|
25 | в отдельных строках, а не как с "сыром"' | |
|
26 | ||
|
27 | !'Общий вид вызова оператора | |
|
28 | имя_оператора аргумент1, аргумент2, ... | |
|
29 | или | |
|
30 | имя_оператора (аргумент1, аргумент2, ...) | |
|
31 | ' | |
|
32 | !Примеры вызовов операторов: | |
|
33 | ADDOBJ 'ключ','pics/key.png' | |
|
34 | ADDOBJ ('ключ','pics/key.png') | |
|
35 | PL ('текст') | |
|
36 | CLEAR() | |
|
37 | ||
|
38 | !Примеры вызовов функций: | |
|
39 | X = MAX(1, 2, 4) | |
|
40 | A = RAND(4) | |
|
41 | B = COUNTOBJ | |
|
42 | PL STR(43) | |
|
43 | PL $STR(43) | |
|
44 | !Последние два выражения эквивалентны | |
|
45 | ||
|
46 | RAND(1,4) &! вернёт случайное значение от 1 до 4 | |
|
47 | RAND(4,1) &! вернёт случайное значение от 1 до 4 | |
|
48 | RAND(1000) &! вернёт случайное значение от 0(1) до 1000 | |
|
49 | RAND 1000 &! вернёт случайное значение от 0(1) до 1000 | |
|
50 | ||
|
51 | MAX(1,2,5,2,0) &! вернёт 5 | |
|
52 | MAX(a,b,c) &! вернёт максимальное из значений переменных a,b,c | |
|
53 | MAX('aa','ab','zz') &! вернёт 'zz' | |
|
54 | MAX('a') &! вернёт максимальное из значений элементов массива "a" | |
|
55 | MAX('$b') &! вернёт максимальное из значений элементов массива "$b" | |
|
56 | - |
@@ -0,0 +1,25 b'' | |||
|
1 | ||
|
2 | # arrays | |
|
3 | $яблоки[0]='антоновка' | |
|
4 | $яблоки[1]='белый налив' | |
|
5 | $яблоки[2]='астраханское' | |
|
6 | $яблоки[3]='ранетка' | |
|
7 | $яблоки[4]='симиренко' | |
|
8 | ||
|
9 | сорт_яблока[0] = 1 | |
|
10 | сорт_яблока[1] = 2 | |
|
11 | сорт_яблока[2] = 4 | |
|
12 | ||
|
13 | *pl $яблоки[сорт_яблока[номер_яблока]] | |
|
14 | ||
|
15 | $любимый_сорт['иван'] = $яблоки[2] | |
|
16 | любимое_число['Алексей'] = 5 | |
|
17 | $item_loc['палка'] = 'лес' | |
|
18 | ||
|
19 | $objs[] = 'Напильник' &! Если массив был пустой, то | |
|
20 | $objs[] = 'Топор' &! [0] = 'Напильник', | |
|
21 | $objs[] = 'Доска' &! [1] = 'Топор', [2] = 'Доска' | |
|
22 | ||
|
23 | $a = $objs[] &! 'Доска' из примера выше | |
|
24 | a = сорт_яблока[] &! 4 из примера выше | |
|
25 | - |
@@ -0,0 +1,19 b'' | |||
|
1 | ||
|
2 | # str | |
|
3 | *PL 'Byte Soft''s "QSP"' | |
|
4 | *PL "Byte Soft's ""QSP""" | |
|
5 | ||
|
6 | 'Данный текст | |
|
7 | будет расположен на | |
|
8 | нескольких строках' | |
|
9 | ||
|
10 | $a='И этот | |
|
11 | текст | |
|
12 | также' | |
|
13 | ||
|
14 | a=2 & act 'Многострочное | |
|
15 | название':gt 'next' & GoTo 'next' | |
|
16 | ||
|
17 | $res = ('x=' & x & ' y=' & y) | |
|
18 | $res = 'x=' & x | |
|
19 | - |
@@ -0,0 +1,56 b'' | |||
|
1 | ||
|
2 | ||
|
3 | # if-elseif | |
|
4 | IF a=1: | |
|
5 | !операторы | |
|
6 | ELSEIF a=2: | |
|
7 | !операторы | |
|
8 | ELSEIF a=3: | |
|
9 | !операторы | |
|
10 | END | |
|
11 | ||
|
12 | - | |
|
13 | ||
|
14 | # if-iif | |
|
15 | !Модуль числа | |
|
16 | abs_x = IIF(x > 0, x, -x) | |
|
17 | ||
|
18 | !А следующая конструкция вызовет ошибку деления на ноль: | |
|
19 | x = 0 | |
|
20 | y = IIF(x = 0, 0, 1/x) | |
|
21 | - | |
|
22 | ||
|
23 | # if-inline | |
|
24 | if ((a+b)/c)=45+54 or (b<5 or c>45) and no obj 'лопата' and $f=$vvv+'RRRRR': p 'OK' & goto 'Next' | |
|
25 | if был_здесь[$curloc]: exit | |
|
26 | if a<3: jump 'sss' | |
|
27 | if $имя = '': msg 'Введите имя!' & jump 'ввод' | |
|
28 | if a+b=2:c=30 & gt 'next' else c=10 & d=11 | |
|
29 | - | |
|
30 | ||
|
31 | # if-lines | |
|
32 | if a+b<3 or y=8: | |
|
33 | p 'A+B<3 или Y=8' | |
|
34 | nl | |
|
35 | if j=88: nl & p 'NEXT' | |
|
36 | if $h='ooo': | |
|
37 | p 'loo' & jump 'lll' | |
|
38 | end | |
|
39 | end | |
|
40 | ||
|
41 | if a=0: | |
|
42 | 'abc1234' | |
|
43 | if b=0: '0' else '1' | |
|
44 | if j=88:nl & p 'NEXT' | |
|
45 | if $h='ooo': | |
|
46 | p 'loo' & jump 'lll' | |
|
47 | else | |
|
48 | p 'sample text' | |
|
49 | v=8 | |
|
50 | end | |
|
51 | '1234' | |
|
52 | else | |
|
53 | '01234' | |
|
54 | g=78 | |
|
55 | end | |
|
56 | - |
@@ -0,0 +1,18 b'' | |||
|
1 | ||
|
2 | # sub | |
|
3 | GS 'переход', 'локация' | |
|
4 | GS 'ход' | |
|
5 | GS $loc,1 | |
|
6 | GS 'ход',$var,2,'данные' | |
|
7 | яблоки = FUNC('функция') | |
|
8 | PL FUNC($name, 1) * 78 | |
|
9 | MSG "text" + FUNC($name, "строка", 2) | |
|
10 | if args[0] = 0: exit | |
|
11 | - | |
|
12 | ||
|
13 | #переход | |
|
14 | *PL $ARGS[0] &! На экран выведется 'локация' | |
|
15 | ACT 'Перейти': | |
|
16 | GT $ARGS[0] &! Работать не будет, т.к. массив ARGS пуст | |
|
17 | END | |
|
18 | - |
@@ -0,0 +1,27 b'' | |||
|
1 | ||
|
2 | # loops | |
|
3 | jump 'КонеЦ' | |
|
4 | p 'Это сообщение не будет выведено' | |
|
5 | :конец | |
|
6 | p 'А это сообщение пользователь увидит' | |
|
7 | ||
|
8 | s=0 | |
|
9 | :loop | |
|
10 | if s<9: | |
|
11 | s=s+1 | |
|
12 | pl s | |
|
13 | jump 'loop' | |
|
14 | end | |
|
15 | p 'Всё!' | |
|
16 | ||
|
17 | :loop | |
|
18 | if y<y0: | |
|
19 | if x<x0: | |
|
20 | x=x+1 | |
|
21 | jump 'loop' | |
|
22 | end | |
|
23 | y=y+1 | |
|
24 | x=0 | |
|
25 | jump 'loop' | |
|
26 | end | |
|
27 | - |
@@ -0,0 +1,24 b'' | |||
|
1 | ("quicklisp" . | |
|
2 | (:class qlot/source/dist:source-dist | |
|
3 | :initargs (:distribution "http://beta.quicklisp.org/dist/quicklisp.txt" :%version :latest) | |
|
4 | :version "2020-02-18")) | |
|
5 | ("alexandria" . | |
|
6 | (:class qlot/source/ql:source-ql | |
|
7 | :initargs (:%version :latest) | |
|
8 | :version "ql-2020-02-18")) | |
|
9 | ("esrap" . | |
|
10 | (:class qlot/source/ql:source-ql | |
|
11 | :initargs (:%version :latest) | |
|
12 | :version "ql-2020-02-18")) | |
|
13 | ("parenscript" . | |
|
14 | (:class qlot/source/ql:source-ql | |
|
15 | :initargs (:%version :latest) | |
|
16 | :version "ql-2020-02-18")) | |
|
17 | ("cl-uglify-js" . | |
|
18 | (:class qlot/source/ql:source-ql | |
|
19 | :initargs (:%version :latest) | |
|
20 | :version "ql-2020-02-18")) | |
|
21 | ("adopt" . | |
|
22 | (:class qlot/source/github:source-github | |
|
23 | :initargs (:repos "sjl/adopt" :ref nil :branch nil :tag nil) | |
|
24 | :version "github-b594120fec8a15c68cae5040f8db6658")) |
@@ -0,0 +1,39 b'' | |||
|
1 | ||
|
2 | (in-package sugar-qsp) | |
|
3 | ||
|
4 | ;;; API deals with DOM manipulation and some bookkeeping for the | |
|
5 | ;;; intrinsics, namely variables | |
|
6 | ;;; API is an implementation detail and has no QSP documentation. It | |
|
7 | ;;; doesn't call intrinsics | |
|
8 | ||
|
9 | (setf (root api) (ps:create)) | |
|
10 | ||
|
11 | ;;; Function calls | |
|
12 | ||
|
13 | (defm (root api init-args) (args) | |
|
14 | (dotimes (i (length args)) | |
|
15 | (if (numberp (elt args i)) | |
|
16 | (set (var args i) (elt args i)) | |
|
17 | (set (var $args i) (elt args i))))) | |
|
18 | ||
|
19 | (defm (root api get-result) () | |
|
20 | (if (not (equal "" (var $result 0))) | |
|
21 | (var $result 0) | |
|
22 | (var result 0))) | |
|
23 | ||
|
24 | ;;; Text windows | |
|
25 | ||
|
26 | (defm (root api add-text) ()) | |
|
27 | (defm (root api get-text) ()) | |
|
28 | (defm (root api clear-text) ()) | |
|
29 | ||
|
30 | ;;; Actions | |
|
31 | ||
|
32 | (defm (root api add-act) ()) | |
|
33 | (defm (root api clear-act) ()) | |
|
34 | ||
|
35 | ;;; Variables | |
|
36 | ||
|
37 | (defm (root api get-var) ()) | |
|
38 | (defm (root api set-var) ()) | |
|
39 | (defm (root api kill-var) ()) |
@@ -0,0 +1,289 b'' | |||
|
1 | ||
|
2 | (in-package sugar-qsp) | |
|
3 | ||
|
4 | ;;;; Intrinsics are functions and procedures defined by the language. | |
|
5 | ;;;; They can call api and deal with locations and other data directly. | |
|
6 | ;;;; Except vars. Use VAR and SET or GET-VAR and SET-VAR api calls. | |
|
7 | ||
|
8 | (setf (root intrinsics) (ps:create)) | |
|
9 | ||
|
10 | ;;; 1loc | |
|
11 | ||
|
12 | (defm (root intrinsics goto) (target &rest args) | |
|
13 | (api-call clear-text :main) | |
|
14 | (apply (root intrinsics xgoto) target args)) | |
|
15 | ||
|
16 | (defm (root intrinsics xgoto) (target &rest args) | |
|
17 | (api-call clear-act) | |
|
18 | (api-call init-args args) | |
|
19 | (setf (root current-location) target) | |
|
20 | (funcall (ps:getprop (root locations) target))) | |
|
21 | ||
|
22 | ;;; 2var | |
|
23 | ||
|
24 | (defm (root intrinsics killvar) (varname &optional (index :whole)) | |
|
25 | (api-call kill-var varname index)) | |
|
26 | ||
|
27 | (defm (root intrinsics killall) () | |
|
28 | (api-call kill-all)) | |
|
29 | ||
|
30 | ;;; 3expr | |
|
31 | ||
|
32 | (defm (root intrinsics obj) (name) | |
|
33 | (funcall (root objs includes) name)) | |
|
34 | ||
|
35 | (defm (root intrinsics loc) () | |
|
36 | (funcall (root locations includes) name)) | |
|
37 | ||
|
38 | (defm (root intrinsics no) (arg) | |
|
39 | (- -1 arg)) | |
|
40 | ||
|
41 | ;;; 4code | |
|
42 | ||
|
43 | (defm (root intrinsics qspver) () | |
|
44 | "0.0.1") | |
|
45 | ||
|
46 | (defm (root intrinsics curloc) () | |
|
47 | (root current-location)) | |
|
48 | ||
|
49 | (defm (root intrinsics rand) (a b) | |
|
50 | (let ((min (min a b)) | |
|
51 | (max (max a b))) | |
|
52 | (+ min (ps:chain *math (random (- max min)))))) | |
|
53 | ||
|
54 | (defm (root intrinsics rnd) () | |
|
55 | (funcall (root intrinsics rand) 1 1000)) | |
|
56 | ||
|
57 | (defm (root intrinsics qspmax) (&rest args) | |
|
58 | (apply (ps:@ *math max) args)) | |
|
59 | ||
|
60 | (defm (root intrinsics qspmin) (&rest args) | |
|
61 | (apply (ps:@ *math min) args)) | |
|
62 | ||
|
63 | ;;; 5arrays | |
|
64 | ||
|
65 | (defm (root intrinsics copyarr) (to from start count) | |
|
66 | (ps:for ((i start)) | |
|
67 | ((< i (min (api-call array-size from) | |
|
68 | (+ start count)))) | |
|
69 | ((incf i)) | |
|
70 | (api-call set-var to (+ start i) | |
|
71 | (api-call get-var from (+ start i))))) | |
|
72 | ||
|
73 | (defm (root intrinsics arrsize) (name) | |
|
74 | (api-call array-size name)) | |
|
75 | ||
|
76 | (defm (root intrinsics arrpos) (name value &optional (start 0)) | |
|
77 | (ps:for ((i start)) ((< i (api-call array-size name))) ((incf i)) | |
|
78 | (when (eq (api-call get-var name i) value) | |
|
79 | (return i))) | |
|
80 | -1) | |
|
81 | ||
|
82 | (defm (root intrinsics arrcomp) (name pattern &optional (start 0)) | |
|
83 | (ps:for ((i start)) ((< i (api-call array-size name))) ((incf i)) | |
|
84 | (when (funcall (ps:getprop (api-call get-var name i) 'match) pattern) | |
|
85 | (return i))) | |
|
86 | -1) | |
|
87 | ||
|
88 | ;;; 6str | |
|
89 | ||
|
90 | (defm (root intrinsics len) (s) | |
|
91 | (length s)) | |
|
92 | ||
|
93 | (defm (root intrinsics mid) (s from &optional count) | |
|
94 | (s.substring from count)) | |
|
95 | ||
|
96 | (defm (root intrinsics ucase) (s) | |
|
97 | (s.to-upper-case)) | |
|
98 | ||
|
99 | (defm (root intrinsics lcase) (s) | |
|
100 | (s.to-lower-case)) | |
|
101 | ||
|
102 | (defm (root intrinsics trim) (s) | |
|
103 | (s.trim)) | |
|
104 | ||
|
105 | (defm (root intrinsics replace) (s from to) | |
|
106 | (s.replace from to)) | |
|
107 | ||
|
108 | (defm (root intrinsics instr) (s subs &optional (start 1)) | |
|
109 | (+ start (ps:chain s (substring (- start 1)) (search subs)))) | |
|
110 | ||
|
111 | (defm (root intrinsics isnum) (s) | |
|
112 | (if (is-na-n s) | |
|
113 | 0 | |
|
114 | -1)) | |
|
115 | ||
|
116 | (defm (root intrinsics val) (s) | |
|
117 | (parse-int s 10)) | |
|
118 | ||
|
119 | (defm (root intrinsics qspstr) (n) | |
|
120 | (+ "" n)) | |
|
121 | ||
|
122 | (defm (root intrinsics strcomp) (s pattern) | |
|
123 | (if (s.match pattern) | |
|
124 | -1 | |
|
125 | 0)) | |
|
126 | ||
|
127 | (defm (root intrinsics strfind) (s pattern group) | |
|
128 | (let* ((re (ps:new (*reg-exp pattern))) | |
|
129 | (match (re.exec s))) | |
|
130 | (match.group group))) | |
|
131 | ||
|
132 | (defm (root intrinsics strpos) (s pattern &optional (group 0)) | |
|
133 | (let* ((re (ps:new (*reg-exp pattern))) | |
|
134 | (match (re.exec s)) | |
|
135 | (found (match.group group))) | |
|
136 | (if found | |
|
137 | (s.search found) | |
|
138 | 0))) | |
|
139 | ||
|
140 | ;;; 7if | |
|
141 | ||
|
142 | (defm (root intrinsics iif) (cond then else) | |
|
143 | (if (= -1 cond) then else)) | |
|
144 | ||
|
145 | ;;; 8sub | |
|
146 | ||
|
147 | (defm (root intrinsics gosub) (target &rest args) | |
|
148 | (conserving-vars (args $args result $result) | |
|
149 | (api-call init-args args) | |
|
150 | (funcall (ps:getprop (root locations) target)) | |
|
151 | (values))) | |
|
152 | ||
|
153 | (defm (root intrinsics func) (target &rest args) | |
|
154 | (conserving-vars (args $args result $result) | |
|
155 | (api-call init-args args) | |
|
156 | (funcall (ps:getprop (root locations) target)) | |
|
157 | (api-call get-result))) | |
|
158 | ||
|
159 | ;;; 9loops | |
|
160 | ||
|
161 | ;;; 10dynamic | |
|
162 | ||
|
163 | (defm (root intrinsics dyneval) (block &rest args) | |
|
164 | (conserving-vars (args $args result $result) | |
|
165 | (api-call init-args args) | |
|
166 | (funcall block) | |
|
167 | (api-call get-result))) | |
|
168 | ||
|
169 | (defm (root intrinsics dynamic) (&rest args) | |
|
170 | (conserving-vars (args $args result $result) | |
|
171 | (api-call init-args args) | |
|
172 | (funcall block) | |
|
173 | (values))) | |
|
174 | ||
|
175 | ;;; 11main | |
|
176 | ||
|
177 | (defm (root intrinsics main-p) (s) | |
|
178 | (api-call add-text :main s)) | |
|
179 | ||
|
180 | (defm (root intrinsics main-pl) () | |
|
181 | (api-call add-text :main (+ s "\n"))) | |
|
182 | ||
|
183 | (defm (root intrinsics main-nl) () | |
|
184 | (api-call add-text :main (+ "\n" s))) | |
|
185 | ||
|
186 | (defm (root intrinsics maintxt) (s) | |
|
187 | (api-call get-text :main)) | |
|
188 | ||
|
189 | (defm (root intrinsics desc) (s) | |
|
190 | (api-call report-error "DESC is not supported")) | |
|
191 | ||
|
192 | (defm (root intrinsics main-clear) () | |
|
193 | (api-call clear-text :main)) | |
|
194 | ||
|
195 | ;;; 12aux | |
|
196 | ||
|
197 | (defm (root intrinsics showstat) ()) | |
|
198 | ||
|
199 | (defm (root intrinsics aux-p) ()) | |
|
200 | ||
|
201 | (defm (root intrinsics aux-pl) ()) | |
|
202 | ||
|
203 | (defm (root intrinsics aux-nl) ()) | |
|
204 | ||
|
205 | (defm (root intrinsics stattxt) ()) | |
|
206 | ||
|
207 | (defm (root intrinsics clear) ()) | |
|
208 | ||
|
209 | (defm (root intrinsics cls) ()) | |
|
210 | ||
|
211 | ;;; 13diag | |
|
212 | ||
|
213 | (defm (root intrinsics msg) ()) | |
|
214 | ||
|
215 | ;;; 14act | |
|
216 | ||
|
217 | (defm (root intrinsics showacts) ()) | |
|
218 | ||
|
219 | (defm (root intrinsics delact) ()) | |
|
220 | ||
|
221 | (defm (root intrinsics curacts) ()) | |
|
222 | ||
|
223 | (defm (root intrinsics cla) ()) | |
|
224 | ||
|
225 | ;;; 15objs | |
|
226 | ||
|
227 | (defm (root intrinsics showobjs) ()) | |
|
228 | ||
|
229 | (defm (root intrinsics addobj) ()) | |
|
230 | ||
|
231 | (defm (root intrinsics delobj) ()) | |
|
232 | ||
|
233 | (defm (root intrinsics killobj) ()) | |
|
234 | ||
|
235 | (defm (root intrinsics countobj) ()) | |
|
236 | ||
|
237 | (defm (root intrinsics getobj) ()) | |
|
238 | ||
|
239 | ;;; 16menu | |
|
240 | ||
|
241 | (defm (root intrinsics menu) ()) | |
|
242 | ||
|
243 | ;;; 17sound | |
|
244 | ||
|
245 | (defm (root intrinsics play) ()) | |
|
246 | ||
|
247 | (defm (root intrinsics isplay) ()) | |
|
248 | ||
|
249 | (defm (root intrinsics close) ()) | |
|
250 | ||
|
251 | (defm (root intrinsics closeall) ()) | |
|
252 | ||
|
253 | ;;; 18img | |
|
254 | ||
|
255 | (defm (root intrinsics refint) ()) | |
|
256 | ||
|
257 | (defm (root intrinsics view) ()) | |
|
258 | ||
|
259 | ;;; 19input | |
|
260 | ||
|
261 | (defm (root intrinsics showinput) ()) | |
|
262 | ||
|
263 | (defm (root intrinsics usertxt) ()) | |
|
264 | ||
|
265 | (defm (root intrinsics cmdclear) ()) | |
|
266 | ||
|
267 | (defm (root intrinsics input) ()) | |
|
268 | ||
|
269 | ;;; 20time | |
|
270 | ||
|
271 | (defm (root intrinsics wait) ()) | |
|
272 | ||
|
273 | (defm (root intrinsics msecscount) ()) | |
|
274 | ||
|
275 | (defm (root intrinsics settimer) ()) | |
|
276 | ||
|
277 | ;;; misc | |
|
278 | ||
|
279 | (defm (root intrinsics rgb) ()) | |
|
280 | ||
|
281 | (defm (root intrinsics openqst) ()) | |
|
282 | ||
|
283 | (defm (root intrinsics addqst) ()) | |
|
284 | ||
|
285 | (defm (root intrinsics killqst) ()) | |
|
286 | ||
|
287 | (defm (root intrinsics opengame) ()) | |
|
288 | ||
|
289 | (defm (root intrinsics savegame) ()) |
@@ -0,0 +1,17 b'' | |||
|
1 | ||
|
2 | (in-package sugar-qsp) | |
|
3 | ||
|
4 | (defun entry-point (&rest args) | |
|
5 | (catch :terminate | |
|
6 | (make-javascript (parse-file (first args))))) | |
|
7 | ||
|
8 | (defun parse-file (filename) | |
|
9 | (p:parse 'sugar-qsp-grammar | |
|
10 | (alexandria:read-file-into-string filename))) | |
|
11 | ||
|
12 | (defun make-javascript (locations) | |
|
13 | (mapcar #'make-javascript locations)) | |
|
14 | ||
|
15 | (defun report-error (fmt &rest args) | |
|
16 | (apply #'format t fmt args) | |
|
17 | (throw :terminate nil)) |
@@ -0,0 +1,7 b'' | |||
|
1 | ||
|
2 | (in-package cl-user) | |
|
3 | ||
|
4 | (defpackage :sugar-qsp | |
|
5 | (:use :cl) | |
|
6 | (:local-nicknames (#:p #:esrap)) | |
|
7 | (:export #:parse-file #:entry-point)) |
|
1 | NO CONTENT: new file 100644, binary diff hidden |
This diff has been collapsed as it changes many lines, (568 lines changed) Show them Hide them | |||
@@ -0,0 +1,568 b'' | |||
|
1 | ||
|
2 | (in-package sugar-qsp) | |
|
3 | ||
|
4 | ;;;; Parses TXT source to an intermediate representation | |
|
5 | ||
|
6 | ;;; Utility | |
|
7 | ||
|
8 | (defun remove-nth (list nth) | |
|
9 | (append (subseq list 0 nth) | |
|
10 | (subseq list (1+ nth)))) | |
|
11 | ||
|
12 | (defun not-quote (char) | |
|
13 | (not (eql #\' char))) | |
|
14 | ||
|
15 | ||
|
16 | (defun not-doublequote (char) | |
|
17 | (not (eql #\" char))) | |
|
18 | ||
|
19 | (defun not-brace (char) | |
|
20 | (not (eql #\} char))) | |
|
21 | ||
|
22 | (defun not-integer (string) | |
|
23 | (when (find-if-not #'digit-char-p string) | |
|
24 | t)) | |
|
25 | ||
|
26 | (defun not-newline (char) | |
|
27 | (not (eql #\newline char))) | |
|
28 | ||
|
29 | (defun id-any-char (char) | |
|
30 | (and | |
|
31 | (not (digit-char-p char)) | |
|
32 | (not (eql #\newline char)) | |
|
33 | (not (find char " !:&=<>+-*/,'\"()[]{}")))) | |
|
34 | ||
|
35 | (defun intern-first (list) | |
|
36 | (list* (intern (string-upcase (first list))) | |
|
37 | (rest list))) | |
|
38 | ||
|
39 | (defun remove-nil (list) | |
|
40 | (remove nil list)) | |
|
41 | ||
|
42 | (defun binop-rest (list) | |
|
43 | (destructuring-bind (ws1 operator ws2 operand2) | |
|
44 | list | |
|
45 | (declare (ignore ws1 ws2)) | |
|
46 | (list (intern (string-upcase operator)) operand2))) | |
|
47 | ||
|
48 | (defun do-binop% (left-op other-ops) | |
|
49 | (if (null other-ops) | |
|
50 | left-op | |
|
51 | (destructuring-bind ((operator right-op) &rest rest-ops) | |
|
52 | other-ops | |
|
53 | (if (eq (first left-op) | |
|
54 | operator) | |
|
55 | (do-binop% (append left-op (list right-op)) rest-ops) | |
|
56 | (do-binop% (list operator left-op right-op) rest-ops))))) | |
|
57 | ||
|
58 | (defun do-binop (list) | |
|
59 | (destructuring-bind (left-op rest-ops) | |
|
60 | list | |
|
61 | (do-binop% left-op | |
|
62 | (mapcar #'binop-rest rest-ops)))) | |
|
63 | ||
|
64 | (p:defrule line-continuation (and #\_ #\newline) | |
|
65 | (:constant nil)) | |
|
66 | ||
|
67 | (p:defrule text-spaces (+ (or #\space #\tab line-continuation)) | |
|
68 | (:text t)) | |
|
69 | ||
|
70 | (p:defrule spaces (+ (or #\space #\tab line-continuation)) | |
|
71 | (:constant nil)) | |
|
72 | ||
|
73 | (p:defrule spaces? (* (or #\space #\tab line-continuation)) | |
|
74 | (:constant nil)) | |
|
75 | ||
|
76 | (p:defrule colon #\: | |
|
77 | (:constant nil)) | |
|
78 | ||
|
79 | (p:defrule alphanumeric (alphanumericp character)) | |
|
80 | ||
|
81 | (p:defrule not-newline (not-newline character)) | |
|
82 | ||
|
83 | (p:defrule squote-esc "''" | |
|
84 | (:lambda (list) | |
|
85 | (p:text (elt list 0)))) | |
|
86 | ||
|
87 | (p:defrule dquote-esc "\"\"" | |
|
88 | (:lambda (list) | |
|
89 | (p:text (elt list 0)))) | |
|
90 | ||
|
91 | (p:defrule sstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "\"exec:"))) | |
|
92 | (or squote-esc (not-quote character)))) | |
|
93 | (:lambda (list) | |
|
94 | (p:text (mapcar #'second list)))) | |
|
95 | ||
|
96 | (p:defrule dstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "'exec:"))) | |
|
97 | (or dquote-esc (not-doublequote character)))) | |
|
98 | (:lambda (list) | |
|
99 | (p:text (mapcar #'second list)))) | |
|
100 | ||
|
101 | ;;; Identifiers | |
|
102 | ||
|
103 | ;; From the official docs | |
|
104 | (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize $backimage bcolor cla clear *clear close clr *clr cls cmdclear cmdclr copyarr $counter countobj $curacts curloc debug delact dellib delobj desc disablescroll disablesubex dynamic dyneval else elseif end exit fcolor $fname freelib fsize func getobj gosub goto gs gt if iif inclib input instr isnum isplay jump killall killobj killqst killvar lcase lcolor len let loc $maintxt max menu mid min mod msecscount msg nl *nl no nosave obj $onactsel $ongload $ongsave $onnewloc $onobjadd $onobjdel $onobjsel opengame openqst or p *p pl *pl play qspver rand refint replace rgb rnd savegame selact selobj set settimer showacts showinput showobjs showstat $stattxt str strcomp strfind strpos trim ucase unsel unselect usehtml $usercom user_text usrtxt val view wait xgoto xgt)) | |
|
105 | ||
|
106 | (defun qsp-keyword-p (id) | |
|
107 | (member (intern (string-upcase id)) *keywords*)) | |
|
108 | ||
|
109 | (defun not-qsp-keyword-p (id) | |
|
110 | (not (member (intern (string-upcase id)) *keywords*))) | |
|
111 | ||
|
112 | (p:defrule qsp-keyword (qsp-keyword-p identifier-raw)) | |
|
113 | ||
|
114 | (p:defrule id-first (id-any-char character)) | |
|
115 | (p:defrule id-next (or (id-any-char character) | |
|
116 | (digit-char-p character))) | |
|
117 | (p:defrule identifier-raw (and id-first (* id-next)) | |
|
118 | (:lambda (list) | |
|
119 | (let ((id (p:text list))) | |
|
120 | (when (member id *keywords*) | |
|
121 | (error "~A is a keyword" id)) | |
|
122 | (intern (string-upcase id))))) | |
|
123 | ||
|
124 | (p:defrule identifier (not-qsp-keyword-p identifier-raw)) | |
|
125 | ||
|
126 | ;;; Strings | |
|
127 | ||
|
128 | (p:defrule qsp-string (or normal-string brace-string)) | |
|
129 | ||
|
130 | (p:defrule normal-string (or sstring dstring) | |
|
131 | (:lambda (str) | |
|
132 | (list* 'str (or str (list ""))))) | |
|
133 | ||
|
134 | (p:defrule sstring (and #\' (* (or string-interpol | |
|
135 | sstring-exec | |
|
136 | sstring-chars)) | |
|
137 | #\') | |
|
138 | (:function second)) | |
|
139 | ||
|
140 | (p:defrule dstring (and #\" (* (or string-interpol | |
|
141 | dstring-exec | |
|
142 | dstring-chars)) | |
|
143 | #\") | |
|
144 | (:function second)) | |
|
145 | ||
|
146 | (p:defrule string-interpol (and "<<" expression ">>") | |
|
147 | (:function second)) | |
|
148 | ||
|
149 | (p:defrule sstring-exec-body (+ (or squote-esc (not-doublequote character))) | |
|
150 | (:text t)) | |
|
151 | ||
|
152 | (p:defrule dstring-exec-body (+ (or dquote-esc (not-quote character))) | |
|
153 | (:text t)) | |
|
154 | ||
|
155 | (p:defrule sstring-exec (and (p:~ "\"exec:") sstring-exec-body #\") | |
|
156 | (:lambda (list) | |
|
157 | (list* 'exec (p:parse 'exec-body (second list))))) | |
|
158 | ||
|
159 | (p:defrule dstring-exec (and (p:~ "'exec:") dstring-exec-body #\') | |
|
160 | (:lambda (list) | |
|
161 | (list* 'exec (p:parse 'exec-body (second list))))) | |
|
162 | ||
|
163 | (p:defrule brace-string (and #\{ before-statement block-body #\}) | |
|
164 | (:lambda (list) | |
|
165 | (list* 'qspblock (third list)))) | |
|
166 | ||
|
167 | ;;; Location | |
|
168 | ||
|
169 | (p:defrule sugar-qsp-grammar (and (* (or spaces #\newline)) | |
|
170 | (* location)) | |
|
171 | (:function second)) | |
|
172 | ||
|
173 | (p:defrule location (and location-header block-body location-end) | |
|
174 | (:destructure (header body end) | |
|
175 | (declare (ignore end)) | |
|
176 | `(location (,header) ,@body))) | |
|
177 | ||
|
178 | (p:defrule location-header (and #\# | |
|
179 | (+ not-newline) | |
|
180 | (and #\newline spaces? before-statement)) | |
|
181 | (:destructure (spaces1 name spaces2) | |
|
182 | (declare (ignore spaces1 spaces2)) | |
|
183 | (string-upcase (string-trim " " (p:text name))))) | |
|
184 | ||
|
185 | (p:defrule location-end (and #\- #\newline before-statement) | |
|
186 | (:constant nil)) | |
|
187 | ||
|
188 | ;;; Block body | |
|
189 | ||
|
190 | (p:defrule newline-block-body (and #\newline spaces? block-body) | |
|
191 | (:function third)) | |
|
192 | ||
|
193 | (p:defrule block-body (* statement) | |
|
194 | (:function remove-nil)) | |
|
195 | ||
|
196 | ;; Just for <a href="exec:...'> | |
|
197 | ;; Explicitly called from that rule's production | |
|
198 | (p:defrule exec-body (and before-statement line-body) | |
|
199 | (:function second)) | |
|
200 | ||
|
201 | (p:defrule line-body (and inline-statement (* next-inline-statement)) | |
|
202 | (:lambda (list) | |
|
203 | (list* (first list) (second list)))) | |
|
204 | ||
|
205 | (p:defrule before-statement (* (or #\newline spaces)) | |
|
206 | (:constant nil)) | |
|
207 | ||
|
208 | (p:defrule statement-end (or statement-end-real statement-end-block-close)) | |
|
209 | ||
|
210 | (p:defrule statement-end-real (and (or #\newline | |
|
211 | (and #\& spaces? (p:& statement%))) | |
|
212 | before-statement) | |
|
213 | (:constant nil)) | |
|
214 | ||
|
215 | (p:defrule statement-end-block-close (or (p:& #\})) | |
|
216 | (:constant nil)) | |
|
217 | ||
|
218 | (p:defrule inline-statement (and statement% spaces?) | |
|
219 | (:function first)) | |
|
220 | ||
|
221 | (p:defrule next-inline-statement (and #\& spaces? inline-statement) | |
|
222 | (:function third)) | |
|
223 | ||
|
224 | (p:defrule not-a-non-statement (and (p:! (p:~ "elseif")) | |
|
225 | (p:! (p:~ "else")) | |
|
226 | (p:! (p:~ "end")))) | |
|
227 | ||
|
228 | (p:defrule statement (and inline-statement statement-end) | |
|
229 | (:function first)) | |
|
230 | ||
|
231 | (p:defrule statement% (and not-a-non-statement | |
|
232 | (or label comment string-output | |
|
233 | block non-returning-intrinsic assignment | |
|
234 | expression-output)) | |
|
235 | (:function second)) | |
|
236 | ||
|
237 | (p:defrule expr-stopper (or comment block non-returning-intrinsic)) | |
|
238 | ||
|
239 | (p:defrule string-output qsp-string | |
|
240 | (:lambda (string) | |
|
241 | (list 'main-pl string))) | |
|
242 | ||
|
243 | (p:defrule expression-output expression | |
|
244 | (:lambda (list) | |
|
245 | (list 'main-pl list))) | |
|
246 | ||
|
247 | (p:defrule label (and colon identifier) | |
|
248 | (:lambda (list) | |
|
249 | (intern (string (second list)) :keyword))) | |
|
250 | ||
|
251 | (p:defrule comment (and #\! (* (or text-spaces qsp-string brace-string not-newline))) | |
|
252 | (:constant nil)) | |
|
253 | ||
|
254 | ;;; Blocks | |
|
255 | ||
|
256 | (p:defrule block (or block-act block-if)) | |
|
257 | ||
|
258 | (p:defrule block-if (and block-if-head block-if-body) | |
|
259 | (:destructure (head body) | |
|
260 | `(qspcond (,@head ,@(first body)) | |
|
261 | ,@(rest body)))) | |
|
262 | ||
|
263 | (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?) | |
|
264 | (:function remove-nil) | |
|
265 | (:function cdr)) | |
|
266 | ||
|
267 | (p:defrule block-if-body (or block-if-ml block-if-sl) | |
|
268 | (:destructure (if-body elseifs else &rest ws) | |
|
269 | (declare (ignore ws)) | |
|
270 | `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else)))))) | |
|
271 | ||
|
272 | (p:defrule block-if-sl (and line-body | |
|
273 | (p:? block-if-elseif-inline) | |
|
274 | (p:? block-if-else-inline) | |
|
275 | spaces?)) | |
|
276 | ||
|
277 | (p:defrule block-if-ml (and (and #\newline spaces?) | |
|
278 | block-body | |
|
279 | (p:? block-if-elseif) | |
|
280 | (p:? block-if-else) | |
|
281 | block-if-end) | |
|
282 | (:lambda (list) | |
|
283 | (cdr list))) | |
|
284 | ||
|
285 | (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline)) | |
|
286 | (:destructure (head statements elseif) | |
|
287 | `((,@(rest head) ,@(remove-nil statements)) ,@elseif))) | |
|
288 | ||
|
289 | (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif)) | |
|
290 | (:destructure (head ws statements elseif) | |
|
291 | (declare (ignore ws)) | |
|
292 | `((,@(rest head) ,@(remove-nil statements)) ,@elseif))) | |
|
293 | ||
|
294 | (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?) | |
|
295 | (:function remove-nil) | |
|
296 | (:function intern-first)) | |
|
297 | ||
|
298 | (p:defrule block-if-else-inline (and block-if-else-head line-body) | |
|
299 | (:function second)) | |
|
300 | ||
|
301 | (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body) | |
|
302 | (:function fourth)) | |
|
303 | ||
|
304 | (p:defrule block-if-else-head (and (p:~ "else") spaces?) | |
|
305 | (:constant nil)) | |
|
306 | ||
|
307 | (p:defrule block-if-end (and (p:~ "end") | |
|
308 | (p:? (and spaces (p:~ "if")))) | |
|
309 | (:constant nil)) | |
|
310 | ||
|
311 | (p:defrule block-act (and block-act-head (or block-act-ml block-act-sl)) | |
|
312 | (:lambda (list) | |
|
313 | (apply #'append list))) | |
|
314 | ||
|
315 | (p:defrule block-act-sl (and line-body #\newline spaces?) | |
|
316 | (:function first)) | |
|
317 | ||
|
318 | (p:defrule block-act-ml (and newline-block-body block-act-end) | |
|
319 | (:lambda (list) | |
|
320 | (apply #'list* (butlast list)))) | |
|
321 | ||
|
322 | (p:defrule block-act-head (and (p:~ "act") spaces qsp-string spaces? | |
|
323 | (p:? block-act-head-img) | |
|
324 | colon spaces?) | |
|
325 | (:lambda (list) | |
|
326 | (intern-first (remove-nil list)))) | |
|
327 | ||
|
328 | (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?) | |
|
329 | (:lambda (list) | |
|
330 | (or (third list) ""))) | |
|
331 | ||
|
332 | (p:defrule block-act-end (and (p:~ "end")) | |
|
333 | (:constant nil)) | |
|
334 | ||
|
335 | ;;; Calls | |
|
336 | ||
|
337 | (p:defrule first-argument (and expression spaces?) | |
|
338 | (:function first)) | |
|
339 | (p:defrule next-argument (and "," spaces? expression) | |
|
340 | (:function third)) | |
|
341 | (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments)) | |
|
342 | (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\)) | |
|
343 | (:function third)) | |
|
344 | (p:defrule plain-arguments (and spaces base-arguments) | |
|
345 | (:function second)) | |
|
346 | (p:defrule no-arguments (or spaces (p:& #\newline) (p:& #\&)) | |
|
347 | (:constant nil)) | |
|
348 | (p:defrule base-arguments (and first-argument (* next-argument)) | |
|
349 | (:destructure (first rest) | |
|
350 | (list* first rest))) | |
|
351 | ||
|
352 | ;;; Intrinsics | |
|
353 | ||
|
354 | (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses) | |
|
355 | `(progn | |
|
356 | ,@(loop :for clause :in clauses | |
|
357 | :collect `(defintrinsic ,@clause)) | |
|
358 | (p:defrule ,returning-rule-name (or ,@(remove-nil | |
|
359 | (mapcar (lambda (clause) | |
|
360 | (when (second clause) | |
|
361 | (alexandria:symbolicate | |
|
362 | 'intrinsic- (first clause)))) | |
|
363 | clauses)))) | |
|
364 | (p:defrule ,non-returning-rule-name (or ,@(remove-nil | |
|
365 | (mapcar (lambda (clause) | |
|
366 | (unless (second clause) | |
|
367 | (alexandria:symbolicate | |
|
368 | 'intrinsic- (first clause)))) | |
|
369 | clauses)))) | |
|
370 | (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name)))) | |
|
371 | ||
|
372 | (defmacro defintrinsic (sym returning &optional (min-arity 0) (max-arity 10) &rest names) | |
|
373 | (declare (ignore returning)) | |
|
374 | (setf names | |
|
375 | (if names | |
|
376 | (mapcar #'string-upcase names) | |
|
377 | (list (string sym)))) | |
|
378 | `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym) | |
|
379 | (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name))) | |
|
380 | arguments) | |
|
381 | (:destructure (dollar name arguments) | |
|
382 | (declare (ignore dollar)) | |
|
383 | (unless (<= ,min-arity (length arguments) ,max-arity) | |
|
384 | (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S" | |
|
385 | name ,min-arity ,max-arity (length arguments) arguments)) | |
|
386 | (list* ',sym arguments)))) | |
|
387 | ||
|
388 | (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic) | |
|
389 | ;; Transitions | |
|
390 | (goto nil 0 10 "gt" "goto") | |
|
391 | (xgoto nil 0 10 "xgt" "xgoto") | |
|
392 | ;; Variables | |
|
393 | (killvar nil 0 2) | |
|
394 | ;; Expressions | |
|
395 | (obj t 1 1) | |
|
396 | (loc t 1 1) | |
|
397 | (no t 1 1) | |
|
398 | ;; Basic | |
|
399 | (qspver t 0 0) | |
|
400 | (curloc t 0 0) | |
|
401 | (rand t 1 2) | |
|
402 | (rnd t 0 0) | |
|
403 | (qspmax t 1 10 "max") | |
|
404 | (qspmin t 1 10 "min") | |
|
405 | ;; Arrays | |
|
406 | (killall nil 0 0) | |
|
407 | (copyarr nil 2 4) | |
|
408 | (arrsize t 1 1) | |
|
409 | (arrpos t 2 3) | |
|
410 | (arrcomp t 2 3) | |
|
411 | ;; Strings | |
|
412 | (len t 1 1) | |
|
413 | (mid t 2 3) | |
|
414 | (ucase t 1 1) | |
|
415 | (lcase t 1 1) | |
|
416 | (trim t 1 1) | |
|
417 | (replace t 2 3) | |
|
418 | (instr t 2 3) | |
|
419 | (isnum t 1 1) | |
|
420 | (val t 1 1) | |
|
421 | (qspstr t 1 1 "str") | |
|
422 | (strcomp t 2 2) | |
|
423 | (strfind t 2 3) | |
|
424 | (strpos t 2 3) | |
|
425 | ;; IF | |
|
426 | (iif t 2 3) | |
|
427 | ;; Subs | |
|
428 | (gosub nil 1 10 "gosub" "gs") | |
|
429 | (func t 1 10) | |
|
430 | (exit nil 0 0) | |
|
431 | ;; Jump | |
|
432 | (jump nil 1 1) | |
|
433 | ;; Dynamic | |
|
434 | (dynamic nil 1 10) | |
|
435 | (dyneval t 1 10) | |
|
436 | ;; Main window | |
|
437 | (main-p nil 1 1 "*p") | |
|
438 | (main-pl nil 1 1 "*pl") | |
|
439 | (main-nl nil 0 1 "*nl") | |
|
440 | (maintxt t 0 0) | |
|
441 | (desc t 1 1) | |
|
442 | (main-clear nil 0 0 "*clear" "*clr") | |
|
443 | ;; Aux window | |
|
444 | (showstat nil 1 1) | |
|
445 | (stat-p nil 1 1 "p") | |
|
446 | (stat-pl nil 1 1 "pl") | |
|
447 | (stat-nl nil 0 1 "nl") | |
|
448 | (stattxt t 0 0) | |
|
449 | (stat-clear nil 0 0 "clear" "clr") | |
|
450 | (cls nil 0 0) | |
|
451 | ;; Dialog | |
|
452 | (msg nil 1 1) | |
|
453 | ;; Acts | |
|
454 | (showacts nil 1 1) | |
|
455 | (delact nil 1 1 "delact" "del act") | |
|
456 | (curacts t 0 0) | |
|
457 | (cla nil 0 0) | |
|
458 | ;; Objects | |
|
459 | (showobjs nil 1 1) | |
|
460 | (addobj nil 1 3 "addobj" "add obj") | |
|
461 | (delobj nil 1 1 "delobj" "del obj") | |
|
462 | (killobj nil 0 1) | |
|
463 | (countobj t 0 0) | |
|
464 | (getobj t 1 1) | |
|
465 | ;; Menu | |
|
466 | (menu nil 1 1) | |
|
467 | ;; Sound | |
|
468 | (play nil 1 2) | |
|
469 | (isplay t 1 1) | |
|
470 | (close nil 1 1) | |
|
471 | (closeall nil 0 0 "close all") | |
|
472 | ;; Images | |
|
473 | (refint nil 0 0) | |
|
474 | (view nil 0 1) | |
|
475 | ;; Fonts | |
|
476 | (rgb t 3 3) | |
|
477 | ;; Input | |
|
478 | (showinput nil 1 1) | |
|
479 | (usertxt t 0 0 "user_text" "usrtxt") | |
|
480 | (cmdclear nil 0 0 "cmdclear" "cmdclr") | |
|
481 | (input t 1 1) | |
|
482 | ;; Files | |
|
483 | (openqst nil 1 1) | |
|
484 | (addqst nil 1 1 "addqst" "addlib" "inclib") | |
|
485 | (killqst nil 1 1 "killqst" "dellib" "freelib") | |
|
486 | (opengame nil 0 1) | |
|
487 | (savegame nil 0 1) | |
|
488 | ;; Real time | |
|
489 | (wait nil 1 1) | |
|
490 | (msecscount t 0 0) | |
|
491 | (settimer nil 1 1)) | |
|
492 | ||
|
493 | ;;; Expression | |
|
494 | ||
|
495 | (p:defrule expression or-expr) | |
|
496 | ||
|
497 | (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr))) | |
|
498 | (:function do-binop)) | |
|
499 | ||
|
500 | (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr))) | |
|
501 | (:function do-binop)) | |
|
502 | ||
|
503 | (p:defrule eq-expr (and cat-expr (* (and spaces? (or "<>" "<=" ">=" "=<" "=>" | |
|
504 | #\= #\< #\> #\!) | |
|
505 | spaces? cat-expr))) | |
|
506 | (:function do-binop)) | |
|
507 | ||
|
508 | (p:defrule cat-expr (and sum-expr (* (and spaces? #\& spaces? (p:! expr-stopper) sum-expr))) | |
|
509 | (:lambda (list) | |
|
510 | (do-binop (list (first list) (mapcar (lambda (l) | |
|
511 | (remove-nth l 3)) | |
|
512 | (second list)))))) | |
|
513 | ||
|
514 | (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr))) | |
|
515 | (:function do-binop)) | |
|
516 | ||
|
517 | (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr))) | |
|
518 | (:function do-binop)) | |
|
519 | ||
|
520 | (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr))) | |
|
521 | (:function do-binop)) | |
|
522 | ||
|
523 | (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr) | |
|
524 | (:lambda (list) | |
|
525 | (let ((expr (remove-nil list))) | |
|
526 | (if (= 1 (length expr)) | |
|
527 | (first expr) | |
|
528 | (intern-first expr))))) | |
|
529 | ||
|
530 | (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr exists-expr) spaces?) | |
|
531 | (:function first)) | |
|
532 | ||
|
533 | (p:defrule paren-expr (and #\( spaces? expression spaces? #\)) | |
|
534 | (:function third)) | |
|
535 | ||
|
536 | (p:defrule or-op (p:~ "or") | |
|
537 | (:constant "or")) | |
|
538 | ||
|
539 | (p:defrule and-op (p:~ "and") | |
|
540 | (:constant "and")) | |
|
541 | ||
|
542 | ;;; Variables | |
|
543 | ||
|
544 | (p:defrule variable (and identifier (p:? array-index)) | |
|
545 | (:destructure (id idx) | |
|
546 | (list 'var id (or idx 0)))) | |
|
547 | ||
|
548 | (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\]) | |
|
549 | (:lambda (list) | |
|
550 | (or (third list) :end))) | |
|
551 | ||
|
552 | (p:defrule assignment (or kw-assignment plain-assignment) | |
|
553 | (:destructure (var eq expr) | |
|
554 | (declare (ignore eq)) | |
|
555 | (list 'set var expr))) | |
|
556 | ||
|
557 | (p:defrule plain-assignment (and variable spaces? #\= spaces? expression) | |
|
558 | (:function remove-nil)) | |
|
559 | (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? plain-assignment) | |
|
560 | (:function third)) | |
|
561 | ||
|
562 | ;;; Non-string literals | |
|
563 | ||
|
564 | (p:defrule literal (or qsp-string brace-string number)) | |
|
565 | ||
|
566 | (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)) | |
|
567 | (:lambda (list) | |
|
568 | (parse-integer (p:text list)))) |
|
1 | NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,194 b'' | |||
|
1 | ||
|
2 | (in-package sugar-qsp) | |
|
3 | ||
|
4 | ;;;; Parenscript macros which make the parser's intermediate | |
|
5 | ;;;; representation directly compilable by Parenscript | |
|
6 | ;;;; Some utility macros for other .ps sources too. | |
|
7 | ||
|
8 | ;;; Utils | |
|
9 | ||
|
10 | (ps:defpsmacro defm (path args &body body) | |
|
11 | `(setf ,path (lambda ,args ,@body))) | |
|
12 | ||
|
13 | (ps:defpsmacro root (&rest path) | |
|
14 | `(ps:@ *sugar-q-s-p ,@path)) | |
|
15 | ||
|
16 | (ps:defpsmacro conserving-vars (vars &body body) | |
|
17 | "Calls body with safely stored away VARS, and restores their values after that returning what BODY returns." | |
|
18 | `(let ((__conserved (list ,@(loop :for var :in vars | |
|
19 | :collect `(var ,var 0))))) | |
|
20 | ,@(loop :for var :in vars | |
|
21 | :collect `(set (var ,var 0) ,(if (char= #\$ (elt (string var) 0)) | |
|
22 | "" 0))) | |
|
23 | (unwind-protect | |
|
24 | (progn ,@body) | |
|
25 | (progn | |
|
26 | ,@(loop :for var :in vars | |
|
27 | :for i from 0 | |
|
28 | :collect `(set (var ,var 0) (ps:@ __conserved ,i))))))) | |
|
29 | ||
|
30 | ;;; Common | |
|
31 | ||
|
32 | (defmacro defpsintrinsic (name) | |
|
33 | `(ps:defpsmacro ,name (&rest args) | |
|
34 | `(funcall (root intrinsics ,',name) | |
|
35 | ,@args))) | |
|
36 | ||
|
37 | (defmacro defpsintrinsics (() &rest names) | |
|
38 | `(progn ,@(loop :for name :in names | |
|
39 | :collect `(defpsintrinsic ,name)))) | |
|
40 | ||
|
41 | (defpsintrinsics () | |
|
42 | killvar obj loc no qspver curloc rand rnd qspmax qspmin killall copyarr arrsize arrpos arrcomp len mid ucase lcase trim replace instr isnum val qspstr strcomp strfind strpos iif gosub func dynamic dyneval main-p main-pl main-nl maintxt main-clear showstat stat-p stat-pl stat-nl stattxt stat-clear cls msg showacts delact curacts cla showobjs addobj delobj killobj countobj getobj menu play isplay close closeall refint view rgb showinput usertxt cmdclear input openqst addqst killqst opengame savegame wait msecscount settimer) | |
|
43 | ||
|
44 | (ps:defpsmacro api-call (func &rest args) | |
|
45 | `(funcall (root api ,func) ,@args)) | |
|
46 | ||
|
47 | (ps:defpsmacro label-block (&body body) | |
|
48 | `(progn | |
|
49 | (defvar __labels) | |
|
50 | ,@body | |
|
51 | (values))) | |
|
52 | ||
|
53 | (ps:defpsmacro big-block (&body body) | |
|
54 | `(ps:try | |
|
55 | (label-block | |
|
56 | ,@body) | |
|
57 | (:catch (exit-p) | |
|
58 | (unless (eq exit-p :exit) | |
|
59 | (throw exit-p))))) | |
|
60 | ||
|
61 | (ps:defpsmacro str (&rest forms) | |
|
62 | (cond ((zerop (length forms)) | |
|
63 | "") | |
|
64 | ((and (= 1 (length forms)) | |
|
65 | (stringp (first forms))) | |
|
66 | (first forms)) | |
|
67 | (t | |
|
68 | `(& ,@forms)))) | |
|
69 | ||
|
70 | ;;; 1loc | |
|
71 | ||
|
72 | (ps:defpsmacro location ((name) &body body) | |
|
73 | `(setf (root locations ,name) | |
|
74 | (big-block | |
|
75 | (tagbody ,@body)))) | |
|
76 | ||
|
77 | (ps:defpsmacro goto (target &rest args) | |
|
78 | `(progn | |
|
79 | (funcall (root intrinsics goto) ,target ,@args) | |
|
80 | (exit))) | |
|
81 | ||
|
82 | (ps:defpsmacro xgoto (target &rest args) | |
|
83 | `(progn | |
|
84 | (funcall (root intrinsics xgoto) ,target ,@args) | |
|
85 | (exit))) | |
|
86 | ||
|
87 | (ps:defpsmacro desc (target) | |
|
88 | (report-error "DESC is not supported")) | |
|
89 | ||
|
90 | ;;; 2var | |
|
91 | ||
|
92 | (ps:defpsmacro var (name index) | |
|
93 | `(api-call get-var ,(string name) ,index)) | |
|
94 | ||
|
95 | (ps:defpsmacro set ((var vname vindex) value) | |
|
96 | (assert (eq var 'var)) | |
|
97 | `(api-call set-var ,(string vname) ,vindex ,value)) | |
|
98 | ||
|
99 | ;;; 3expr | |
|
100 | ||
|
101 | (ps:defpsmacro <> (op1 op2) | |
|
102 | `(not (equal ,op1 ,op2))) | |
|
103 | ||
|
104 | (ps:defpsmacro ! (op1 op2) | |
|
105 | `(not (equal ,op1 ,op2))) | |
|
106 | ||
|
107 | ;;; 4code | |
|
108 | ||
|
109 | (ps:defpsmacro exec (&body body) | |
|
110 | (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps:ps* body))) | |
|
111 | ||
|
112 | ;;; 5arrays | |
|
113 | ||
|
114 | ;;; 6str | |
|
115 | ||
|
116 | (ps:defpsmacro & (&rest args) | |
|
117 | `(ps:chain "" (concat ,@args))) | |
|
118 | ||
|
119 | ;;; 7if | |
|
120 | ||
|
121 | (ps:defpsmacro qspcond (&rest clauses) | |
|
122 | `(cond ,@(loop :for clause :in clauses | |
|
123 | :collect (list (first clause) | |
|
124 | `(tagbody ,@(rest clause)))))) | |
|
125 | ||
|
126 | ;;; 8sub | |
|
127 | ||
|
128 | ;;; 9loops | |
|
129 | ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels | |
|
130 | ||
|
131 | (ps:defpsmacro jump (target) | |
|
132 | `(return-from ,(intern (string-upcase (second target))) | |
|
133 | (funcall (ps:getprop __labels ,target)))) | |
|
134 | ||
|
135 | (ps:defpsmacro tagbody (&body body) | |
|
136 | (let ((funcs (list nil :__nil))) | |
|
137 | (dolist (form body) | |
|
138 | (cond ((keywordp form) | |
|
139 | (setf (first funcs) (reverse (first funcs))) | |
|
140 | (push form funcs) | |
|
141 | (push nil funcs)) | |
|
142 | (t | |
|
143 | (push form (first funcs))))) | |
|
144 | (setf (first funcs) (reverse (first funcs))) | |
|
145 | (setf funcs (reverse funcs)) | |
|
146 | (if (= 2 (length funcs)) | |
|
147 | `(progn | |
|
148 | ,@body) | |
|
149 | `(progn | |
|
150 | (setf ,@(loop :for f :on funcs :by #'cddr | |
|
151 | :append (list `(ps:@ __labels ,(first f)) | |
|
152 | `(block ,(intern (string-upcase (string (first f)))) | |
|
153 | ,@(second f) | |
|
154 | ,@(when (third f) | |
|
155 | `((funcall | |
|
156 | (ps:getprop __labels ,(third f))))))))) | |
|
157 | (jump (str "__nil")))))) | |
|
158 | ||
|
159 | (ps:defpsmacro exit () | |
|
160 | `(throw :exit)) | |
|
161 | ||
|
162 | ;;; 10dynamic | |
|
163 | ||
|
164 | (ps:defpsmacro qspblock (&body body) | |
|
165 | `(lambda () | |
|
166 | (defvar __labels) | |
|
167 | ,@body | |
|
168 | (values))) | |
|
169 | ||
|
170 | ;;; 11main | |
|
171 | ||
|
172 | (ps:defpsmacro act (name &body body) | |
|
173 | `(api-call add-act ,name (lambda () | |
|
174 | (big-block | |
|
175 | (tagbody | |
|
176 | ,@body))))) | |
|
177 | ||
|
178 | ;;; 12aux | |
|
179 | ||
|
180 | ;;; 13diag | |
|
181 | ||
|
182 | ;;; 14act | |
|
183 | ||
|
184 | ;;; 15objs | |
|
185 | ||
|
186 | ;;; 16menu | |
|
187 | ||
|
188 | ;;; 17sound | |
|
189 | ||
|
190 | ;;; 18img | |
|
191 | ||
|
192 | ;;; 19input | |
|
193 | ||
|
194 | ;;; 20time |
@@ -0,0 +1,9 b'' | |||
|
1 | ||
|
2 | (in-package sugar-qsp) | |
|
3 | ||
|
4 | ;;; 1. Generates parenscript source to write to js | |
|
5 | ;;; 2. Collects everything into complete file, leaving a neatly marked | |
|
6 | ;;; place to customize page layout and styles. | |
|
7 | ||
|
8 | (defun make-javascript (locations) | |
|
9 | (mapcar #'ps:ps* locations)) |
@@ -0,0 +1,10 b'' | |||
|
1 | ||
|
2 | (defsystem sugar-qsp | |
|
3 | :description "QSP compiler to monolithic HTML page" | |
|
4 | :depends-on (:alexandria :esrap :parenscript :cl-uglify-js) | |
|
5 | :pathname "src/" | |
|
6 | :serial t | |
|
7 | :components ((:file "package") | |
|
8 | (:file "main") | |
|
9 | (:file "ps-macros") | |
|
10 | (:file "parser"))) |
@@ -1,2 +1,44 b'' | |||
|
1 | (Russian readme below) | |
|
1 | 2 | # sugar-qsp |
|
2 | 3 | Compiler for QSP games which creates monolithic HTML pages. |
|
4 | ||
|
5 | ## Usage | |
|
6 | ||
|
7 | There are three mastery levels | |
|
8 | ||
|
9 | 1. Just build me the game: | |
|
10 | ||
|
11 | `sugar-qsp game.txt` | |
|
12 | And it will create the game in game.html | |
|
13 | ||
|
14 | 2. I know what I'm doing: | |
|
15 | `sugar-qsp game.txt -o game.html --body body.html --js jquery.js my-js-library.js --css styles/*.css` | |
|
16 | All options are self-explanatory. The result is a monolithic html specified | |
|
17 | with the `-o` option. Default `body.html` (used by the first mastery level) can | |
|
18 | be found in `extas` directory. | |
|
19 | ||
|
20 | 3. I'm a frontend developer! | |
|
21 | `sugar-qsp game.txt -c -o game.js` | |
|
22 | It just builds the game script into a js you can put on your website. To run | |
|
23 | the game execute `SugarQSP.start()` | |
|
24 | ||
|
25 | # sugar-qsp | |
|
26 | Компилятор для игр на QSP создающий монолитные страницы на HTML. | |
|
27 | ||
|
28 | ## Инструкции | |
|
29 | ||
|
30 | Есть три уровня мастерства. | |
|
31 | ||
|
32 | 1. Просто собери мне игру: | |
|
33 | `sugar-qsp game.txt` | |
|
34 | Создаст игру в game.html | |
|
35 | ||
|
36 | 2. Я знаю что делаю: | |
|
37 | `sugar-qsp game.txt -o game.html --body body.html --js jquery.js my-js-library.js --css styles/*.css` | |
|
38 | Если вы знаете что делаете, то для вас смысл опций очевиден. `body.html` | |
|
39 | по-умолчанию лежит в каталоге `extras`. | |
|
40 | ||
|
41 | 3. Я - фронтендер! | |
|
42 | `sugar-qsp game.txt -c -o game.js` | |
|
43 | Просто соберёт игру в Javascript файл который вы можете разместить на своём | |
|
44 | сайте как вам угодно. Для запуска игры вызовите `SugarQSP.start()`. |
General Comments 0
You need to be logged in to leave comments.
Login now