From f76b5c932422630e69a443b4893e326de4a15362 Mon Sep 17 00:00:00 2001 From: jlchmura Date: Tue, 24 Dec 2024 13:55:28 +0000 Subject: [PATCH 1/4] add lpc submodule --- .gitmodules | 3 +++ vendor/grammars/lpc-language-server | 1 + 2 files changed, 4 insertions(+) create mode 160000 vendor/grammars/lpc-language-server diff --git a/.gitmodules b/.gitmodules index 65d5ef54e..41a017ca1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1446,3 +1446,6 @@ [submodule "vendor/grammars/zephir-sublime"] path = vendor/grammars/zephir-sublime url = https://github.com/phalcon/zephir-sublime +[submodule "vendor/grammars/lpc-language-server"] + path = vendor/grammars/lpc-language-server + url = https://github.com/jlchmura/lpc-language-server.git diff --git a/vendor/grammars/lpc-language-server b/vendor/grammars/lpc-language-server new file mode 160000 index 000000000..9ed1d0b84 --- /dev/null +++ b/vendor/grammars/lpc-language-server @@ -0,0 +1 @@ +Subproject commit 9ed1d0b84a088907b0da35b1722a98ea3e90eba5 From 9909db87b0e8a957a5a85d51fbb743a2d2f61c6d Mon Sep 17 00:00:00 2001 From: jlchmura Date: Tue, 24 Dec 2024 13:55:46 +0000 Subject: [PATCH 2/4] add lpc language, samples, heuristics --- .gitmodules | 6 +- grammars.yml | 3 + lib/linguist/heuristics.yml | 10 + lib/linguist/languages.yml | 9 + samples/LPC/area_env.h | 4 + samples/LPC/convo.c | 642 ++++++++++++++++++ samples/LPC/globals.h | 15 + samples/LPC/startroom.c | 53 ++ vendor/README.md | 1 + .../git_submodule/lpc-language-server.dep.yml | 31 + 10 files changed, 771 insertions(+), 3 deletions(-) create mode 100644 samples/LPC/area_env.h create mode 100644 samples/LPC/convo.c create mode 100644 samples/LPC/globals.h create mode 100644 samples/LPC/startroom.c create mode 100644 vendor/licenses/git_submodule/lpc-language-server.dep.yml diff --git a/.gitmodules b/.gitmodules index 41a017ca1..251b048d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -881,6 +881,9 @@ [submodule "vendor/grammars/logtalk.tmbundle"] path = vendor/grammars/logtalk.tmbundle url = https://github.com/textmate/logtalk.tmbundle +[submodule "vendor/grammars/lpc-language-server"] + path = vendor/grammars/lpc-language-server + url = https://github.com/jlchmura/lpc-language-server.git [submodule "vendor/grammars/lua.tmbundle"] path = vendor/grammars/lua.tmbundle url = https://github.com/LuaLS/lua.tmbundle.git @@ -1446,6 +1449,3 @@ [submodule "vendor/grammars/zephir-sublime"] path = vendor/grammars/zephir-sublime url = https://github.com/phalcon/zephir-sublime -[submodule "vendor/grammars/lpc-language-server"] - path = vendor/grammars/lpc-language-server - url = https://github.com/jlchmura/lpc-language-server.git diff --git a/grammars.yml b/grammars.yml index 219734dcf..33375ccd0 100644 --- a/grammars.yml +++ b/grammars.yml @@ -837,6 +837,9 @@ vendor/grammars/logos: - source.logos vendor/grammars/logtalk.tmbundle: - source.logtalk +vendor/grammars/lpc-language-server: +- documentation.injection.lpc +- source.lpc.lang-server vendor/grammars/lua.tmbundle: - source.lua vendor/grammars/m3: diff --git a/lib/linguist/heuristics.yml b/lib/linguist/heuristics.yml index 923303e6d..4334cc318 100644 --- a/lib/linguist/heuristics.yml +++ b/lib/linguist/heuristics.yml @@ -146,6 +146,12 @@ disambiguations: rules: - language: XML pattern: '^(\s*)(?i:query_name())); + lastPlayer = p; + return p; +} +public query_lastPlayer() { + return (!lastPlayer && parentConvo) + ? parentConvo->query_lastPlayer() + : lastPlayer; +} + +/** indicates if the convo should destruct when it is finished */ +public set_destructOnEnd(int flag) { + destructOnEnd = flag; +} + +set_parentConvo(object c) { + parentConvo=c; +} +object query_parentConvo() { return parentConvo; } + +/** The owner is the actor this convo corresponds to. Usually a monster. */ +set_owner(object o) { + owner = o; + return o; +} +object query_owner() { return owner; } + +/** the operation queue for this conversation. don't mess with this */ +set_queue(mixed *q) { + queue = q; + return q; +} +query_queue() { return queue; } + +/** + * sets the autostart flag. + * the default (1) will cause the convo to autostart when an operation is added + * otherwise you will have to manually call convo->start() + */ +set_auto_start(int s) { + auto_start = s; + return 1; +} +int query_auto_start() { return auto_start; } + +/** + * (Optional) + * Sets the object in which the "on_convoFinished(convoId)" function + * function will be called when the conversation ends. + * @param ob - object or string + */ +set_onFinishOb(mixed ob) { + if (objectp(ob)) + onFinishOb = object_name(ob); + else + onFinishOb = ob; + return convoId; +} +query_onFinishOb() { return onFinishOb; } + +query_convoId() { return convoId; } + +/** + * Stops the current conversation. + * This will also fire on_convoFinished + * @param reason - the reason the convo was stopped + */ +public varargs stop(int reason) { + debug(sprintf("stop request convo %d reason %d", convoId, reason)); + + if (onFinishOb) { + onFinishOb->on_convoFinished(convoId, reason); + } + + queue_status=0; + while(remove_call_out("exec_next_op") != -1); + + if (destructOnEnd) { + destruct(TO); + } + + return 1; +} + +/********** CONVO OPS ***************/ + +/** + * Random Op + * execute a random op from a sub-convo + * @param subConvo - the convo object to execute a random op from + */ +private execOpRandom(object subConvo) { + debug(sprintf("random op %d", convoId)); + if (queue_status==1) { + mixed *ops = subConvo->query_queue(); + int opIdx = RANDBETWEEN(0,sizeof(ops)); + subConvo->execOp(ops[opIdx]); + } else { + debug(sprintf("convo stopped, aborting random op %d", convoId)); + subConvo->stop(); + } +} + +/** + * Repeat Op + * starts the convo over at the beginning, + * but does not erase the queue + */ +execOpRepeat() { + debug(sprintf("repeat convo %d", convoId)); + if (queue_status==1) { + lastIdx=0; + queue_status = 0; + start_internal(); + } else { + debug(sprintf("convo was stopped, skipping repeat %d", convoId)); + } +} + +/** + * Executes a conversation op + * @param op - the operation to execute + */ +public int execOp(mixed op) { + if (!owner) { + debug(sprintf("convo %d has no owner, aborting current op", convoId)); + stop(STOP_REASON_ABORTED); + return 0; + } else if (parentConvo && !parentConvo->query_isRunning()) { + debug(sprintf("convo %d parent has stopped, aborting current op", convoId)); + stop(STOP_REASON_ABORTED); + return 0; + } + + object room = ENV(owner); // get current room of monster + + if (op["closure"]) { + apply(op["closure"], room); + } else if (op["repeat"]) { + execOpRepeat(); + return 0; + } else if (op["delay"]) { + lastIdx++; + call_out("exec_next_op",op["delay"]); + return 0; + } else if (op["random"]) { + execOpRandom(op["random"]); + } else if (op["waitfor"]) { + // start timeout if there is one + while (remove_call_out("waitfor_ttlExpired") != -1); + int ttl = op["waitfor"]["matchset"]->query_ttl(); + if (ttl) { + call_out("waitfor_ttlExpired",ttl); + } + + // if there is a promptset, then start it + object ps = op["waitfor"]["promptset"]; + if (objectp(ps)) { + debug("got a promptset"); + ps->start_internal(); + currentPromptSet = ps; + } + + return 0; // exit here. catch_tell will advance index + } + + // check to make sure the op didn't stop the queue + if (queue_status) { + return 1; + } else { + debug(sprintf("Convo %d was stopped by op", convoId)); + if (destructOnEnd) { + destruct(TO); + } + } + + return 0; +} + +/** + * Executes the next op into the convo queue + */ +exec_next_op() { + debug(sprintf("convo=%d, exec next %d",convoId, lastIdx)); + + // exit if there is nothing left to do + if (!queue || lastIdx >= sizeof(queue)) { + if (lastIdx >= sizeof(queue)) { + // convo has finished + // notify any objects that are waiting + stop(); + } + + queue_status=0; + lastIdx=0; + queue = ({}); // cleanup + return; + } + + // get the next op and execute it + mixed op = queue[lastIdx]; + int execNext = execOp(op); + + // execute the next op if appropriate + if (execNext) { + lastIdx++; + exec_next_op(); + } +} + +public start_internal() { + + debug(sprintf("convo %d start. queue size is %d, status is %d",convoId, sizeof(queue), queue_status)); + if (queue_status) return 0; + + queue_status=1; + call_out("exec_next_op", 0); + + return queue_status; + +} + +/** + * Start the queue + */ +public start() { + return start_internal(); +} + +public try_auto_start() { + if (auto_start && !queue_status) { + debug(sprintf("convo %d autostarted", convoId)); + return start_internal(); + } + + return 0; +} + +/** + * this will stop execution of the existing conversation + * and clear any queued operations + */ +public restart() { + destructConvos(); + + queue_status = 0; + queue = ({}); + lastIdx = 0; + while(remove_call_out("exec_next_op") != -1); + + debug(sprintf("convo %d restarted", convoId)); + + return 1; +} + +/************ OP CREATION METHODS **************/ + +/** + * Speak operation + * Will display a message in the owner's current environment. + * The message will be prefixed with: [Short Name] says: + * @param s - the message to display + * @param to - an optional player name or object to speak to + */ +public varargs speak(string s, mixed to) { + if (to) { + object player; + if (stringp(to)) { + player = find_living(to); + } else if (objectp(to) && living(to)) { + player = to; + } else { + throw("to was not a string or object"); + } + + closure op = (: + if (ENV(player) == $1) { + string nm = owner->query_short(); + string pNm = player->query_name(); + string pfxO = sprintf("%s says [to you]: ", nm); + string pfxR = sprintf("%s says [to %s]: ", nm, pNm); + tell_object(to, sprintf("%s%s\n", pfxO, s), strlen(pfxO)); + tell_room( + $1, + sprintf("%s%s\n", pfxR, s), + ({ player, owner }), + strlen(pfxR) + ); + } + return 1; + :); + queue += ({ ([ "closure": op ]) }); + } else { + string pfx = sprintf("%s says: ", owner->query_short()); + string msg = sprintf("%s%s\n", pfx, s); + + closure op = (: tell_room($1, msg, ({ owner })), strlen(pfx) :); + queue += ({ ([ "closure": op ]) }); + } + + try_auto_start(); + return TO; +} + +/** + * Delay operation + * Pauses execution for t seconds + */ +public delay(int t) { + queue += ({ ([ "delay": t ]) }); + try_auto_start(); + return TO; +} + +/** + * Tell operation + * Will display message "s" to player "player" via a tell mechanism + * The message will be prefixed with: Short Name tells you: + */ +public tell(string player, string s) { + string msg = sprintf("%s tells you: %s\n", owner->query_short(), s); + + closure op = (: object p=find_player(player); if(p) { tell_object(p, msg); } return; :); + queue += ({ ([ "closure": op ]) }); + + try_auto_start(); + return TO; +} + +/** + * Emote operation + * The message e will be displayed in the owner's current environment. + * The message will be prefixed with: Short Name. + * Eg: + * ->emote("giggles") + * Output: + * Scarry Monster giggles + */ +public emote(string e) { + object room = ENV(owner); + string msg = sprintf("%s %s\n", owner->query_short(), e); + + closure op = (: tell_room($1, msg, ({ owner })) :); + queue += ({ ([ "closure": op ]) }); + + try_auto_start(); + return TO; +} + +/** + * Wait For Operation + * This will pause execution of the current convo queue until either + * a message has been received that matches one of the conditions in the + * matchset, or until the matchsets timeout has elapsed. + * + * An optional promptset can be provided which is a convo queue that will + * execute while the owner is waiting for an appropriate response. + * + * Note: For the wait_for operation to work correctly, the monster must pipe + * it's catch_tell specifically to the convo object. + * Example: + * if ("convo"::catch_tell(str)) { + * return 1; + * } else { + * return ::catch_tell(str); + * } + */ +public varargs wait_for(object _matchset, object _promptset) { + debug(sprintf("waitfor types: %d and %d", typeof(_matchset), typeof(_promptset))); + object *wf = ([ "matchset": _matchset ]); + + // TODO typecheck these objects + if (objectp(_promptset)) { + wf["promptset"] = _promptset; + } + + queue += ({ ([ "waitfor": wf ]) }); + + try_auto_start(); + return TO; +} + +/** + * Matchset operation. + * Creates a new matchset + */ +public matchset() { + object m = clone_object(MATCHSET_OB); + return m; +} + +/** + * Promptset operation + * Creates a new promptset, which is really just another convo object + */ +public promptset() { + debug("created prompset"); + // a promptset is just a convo + return convo(); +} + +/** + * Stop All operation + * Stops this convo and all upstream convo's + */ +public stopall() { + object currentConvo = TO; + closure op = (: TO->stop(STOP_REASON_STOPALL) :); + queue += ({ ([ "closure": op ]) }); + + return TO; +} + +/** + * Random operation + * Accepts a convo object as a parameter and will execute a random op from + * that sub-convo's queue. Note the ops in the sub-convo will not be executed + * sequentially. Only a single op will be executed. + */ +public random(object convo) { + + // TODO: typecheck the convo object + convo->set_parentConvo(TO); + queue += ({ ([ "random": convo ]) }); + + return TO; +} + +/** + * Repeat operation + * Causes the current convo queue to start over at the beginning. + * Make sure there is some sort of delay in your queue so that you don't + * flood the user with output + */ +public repeat() { + queue += ({ ([ "repeat": 1 ])}); + return TO; +} + +/** + * Convo operation + * Creates a new conversation queue + */ + convo() { + object c = clone_object(CONVO_OB); + c->set_owner(query_owner()); + c->set_parentConvo(TO); + c->set_auto_start(0); + + childConvos += ({ c }); + + return c; +} + +/** + * Function operation + * Will execute a function via call_other on the owner object. + */ +fn(string func, varargs mixed *args) { + + object currentConvo = TO; + closure op = (: call_other(owner, func, currentConvo, args...) :); + queue += ({ ([ "closure": op ]) }); + try_auto_start(); + return TO; + +} + +/** + * Execute a sub operation used by the wait_for mechanics + */ +execute_sub_op(mixed op) { + // what are we executing? + if (objectp(op)) debug(sprintf("exec subop type: %s", load_name(op))); + + if (objectp(op) && load_name(op)==CONVO_OB) { + debug("exec subop convo"); + // branch convo, execute and wait for response + waitForConvoToFinish = op->set_onFinishOb(TO); + op->start_internal(); + return 0; // exit here so the next op does not get executed + } else { + debug("unhandled subop"); + } + + lastIdx++; + exec_next_op(); + + return 1; +} + +/** + * called when the wait_for's ttl has expired + */ +waitfor_ttlExpired() { + catch_tell("***TTL_EXPIRED***"); +} + +/** + * Stops the current promptset, if there is one + */ +stop_promptSet() { + + debug("Stopping promptset"); + + if (currentPromptSet) { + currentPromptSet->stop(); + currentPromptSet = 0; + + debug("Promptset stopped"); + } + +} + +/** + * Handle incoming messages + */ +catch_tell(string str) { + debug("incoming tell: " + str); + + if (!TP || !interactive(TP)) { + debug("TP not interactive"); + return; + } + + if (!queue || lastIdx >= sizeof(queue)) { + debug("queue not running"); + queue_status=0; + return; + } + + // peak at the next op, if it a wait type and we're not waiting + // for a branch convo to finish, then proceed + object op = queue[lastIdx]; + if (op && mappingp(op) && op["waitfor"]) { + object matches = op["waitfor"]["matchset"]; + + // handle TTL expiration + if (matches->query_ttl() && str=="***TTL_EXPIRED***") { + debug("handling ttl expired"); + while (remove_call_out("waitfor_ttlExpired") != -1); + stop_promptSet(); + execute_sub_op(matches->query_ttl_op()); + } + + // only check if we're not waiting for a convo + if (!waitForConvoToFinish) { + foreach(mixed *m in matches->query_matchset()) { + string pat = m[0]; + mixed resp = m[1]; + if (sizeof(regexp(({str}), pat)) > 0) { + set_lastPlayer(TP); // store the player that interacted here + while (remove_call_out("waitfor_ttlExpired") != -1); + stop_promptSet(); + execute_sub_op(resp); + return; + } + } + + debug("no responses matched"); + } + } +} + +/** + * Handles the on_convoFinished fired from sub-convos (usually in the context) + * of a wait_for's promptset + */ +on_convoFinished(int convoId, int reason) { + debug(sprintf("onfinished %d reason %d",convoId, reason)); + if (waitForConvoToFinish==convoId) { + waitForConvoToFinish = 0; + if (reason == STOP_REASON_STOPALL) { + stop(STOP_REASON_STOPALL); + } else { + lastIdx++; + exec_next_op(); + } + } +} + +/** + * does some cleanup by destructing all child convos + */ +public destructConvos() { + foreach(object c in childConvos) { + if (c) c->destructConvos(); + destruct(c); + } + + childConvos -= ({ 0 }); +} \ No newline at end of file diff --git a/samples/LPC/globals.h b/samples/LPC/globals.h new file mode 100644 index 000000000..4376f0337 --- /dev/null +++ b/samples/LPC/globals.h @@ -0,0 +1,15 @@ + +#ifndef GLOBAL_H + +#define GLOBAL_H + +#include +#include "../area.h" + +#define SETWRAP set_wrap_long(1) +#define WRAP(x) wrap_text(x) +#define AREAPATH "/d/area/" +#define ROOMPATH AREAPATH "rooms/" +#define TO this_object() + +#endif \ No newline at end of file diff --git a/samples/LPC/startroom.c b/samples/LPC/startroom.c new file mode 100644 index 000000000..44a18e8e8 --- /dev/null +++ b/samples/LPC/startroom.c @@ -0,0 +1,53 @@ +inherit "room/room"; + +#include "globals.h" + +void reset(int arg) { + ::reset(arg); + + SETWRAP; + + if(!arg) { + + set_light(1); + no_castle_flag = 1; + + short_desc = "Along the edge of a field."; + long_desc = + "You are standing along the western edge of the fields where the " + + "city grows its crops. " + + "A long, straight path heading east has been cut deep in to the middle " + + "of the crops. " + + "Far off to the west you see the tree line of a forest." + ; + + dest_dir = ({ + "room/crop", "east", + ROOMPATH + "treeline.c", "west" + }); + + items = ({ + ({"crops", "crop","field"}), + WRAP( + "A large field of crops that extends east as far as the eye can see. "+ + "There is a path heading east, in to the field." + ), + ({"tree", "trees", "tree line"}), + "The edge of a forest made up of some species of pine tree." + }); + + search_items = ({ + ({"crop", "crops", "field"}), "It looks like corn.", + }); + + sounds = + ({ + "", "You can hear the breeze rustling through the stalks in the field.", + }); + + if (!present("bulletin board")) { + move_object(AREAPATH+"obj/board.c", TO); + } + } +} + diff --git a/vendor/README.md b/vendor/README.md index f2b1a53f6..dcc523cfe 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -308,6 +308,7 @@ This is a list of grammars that Linguist selects to provide syntax highlighting - **LFE:** [textmate/lisp.tmbundle](https://github.com/textmate/lisp.tmbundle) - **LLVM:** [whitequark/llvm.tmbundle](https://github.com/whitequark/llvm.tmbundle) - **LOLCODE:** [KrazIvan/LOLCODE-grammar-vscode](https://github.com/KrazIvan/LOLCODE-grammar-vscode) +- **LPC:** [jlchmura/lpc-language-server](https://github.com/jlchmura/lpc-language-server) - **LSL:** [textmate/secondlife-lsl.tmbundle](https://github.com/textmate/secondlife-lsl.tmbundle) - **LTspice Symbol:** [Alhadis/language-pcb](https://github.com/Alhadis/language-pcb) - **LabVIEW:** [textmate/xml.tmbundle](https://github.com/textmate/xml.tmbundle) diff --git a/vendor/licenses/git_submodule/lpc-language-server.dep.yml b/vendor/licenses/git_submodule/lpc-language-server.dep.yml new file mode 100644 index 000000000..98cac3f6d --- /dev/null +++ b/vendor/licenses/git_submodule/lpc-language-server.dep.yml @@ -0,0 +1,31 @@ +--- +name: lpc-language-server +version: 9ed1d0b84a088907b0da35b1722a98ea3e90eba5 +type: git_submodule +homepage: https://github.com/jlchmura/lpc-language-server.git +license: mit +licenses: +- sources: LICENSE + text: | + MIT License + + Copyright (c) 2023-2024 John Chmura + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +notices: [] From 3bde0c15ed65cff53575adb113f8e1f5011c1ea3 Mon Sep 17 00:00:00 2001 From: jlchmura Date: Tue, 24 Dec 2024 09:17:50 -0500 Subject: [PATCH 3/4] add more lpc heuristics --- lib/linguist/heuristics.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/linguist/heuristics.yml b/lib/linguist/heuristics.yml index 4334cc318..4cb460cc2 100644 --- a/lib/linguist/heuristics.yml +++ b/lib/linguist/heuristics.yml @@ -956,7 +956,7 @@ named_patterns: - '^[ \t]*#[ \t]*(?:precache|using_animtree)[ \t]*\(' json: '\A\s*[{\[]' key_equals_value: '^[^#!;][^=]*=' - lpc: '(mixed|nosave|clone_object)|(^inherit [\"A-Za-z][A-Za-z0-9_]*)|(((public|private|protected)\s+)?((varargs|nomask|noshadow)+\s+)?((string|int|mixed|object|mapping)\s+)?[A-Za-z][A-Za-z0-9_]*\()' + lpc: '(mixed|nosave|clone_object)|(this_player\(\))|(^inherit [\"A-Za-z][A-Za-z0-9_]*)|(((public|private|protected)\s+)?((varargs|nomask|noshadow)+\s+)?((string|int|mixed|object|mapping)\s+)?[A-Za-z][A-Za-z0-9_]*\()' m68k: - '(?im)\bmoveq(?:\.l)?\s+#(?:\$-?[0-9a-f]{1,3}|%[0-1]{1,8}|-?[0-9]{1,3}),\s*d[0-7]\b' - '(?im)^\s*move(?:\.[bwl])?\s+(?:sr|usp),\s*[^\s]+' From 29a0af5aa6f51687df7460aa690c541b8fd33aa9 Mon Sep 17 00:00:00 2001 From: jlchmura Date: Tue, 24 Dec 2024 09:26:27 -0500 Subject: [PATCH 4/4] add more LPC samples from language server --- samples/LPC/array2.c | 7 +++++++ samples/LPC/callOther3.c | 7 +++++++ samples/LPC/closures.c | 8 ++++++++ samples/LPC/uniontypes.c | 5 +++++ 4 files changed, 27 insertions(+) create mode 100644 samples/LPC/array2.c create mode 100644 samples/LPC/callOther3.c create mode 100644 samples/LPC/closures.c create mode 100644 samples/LPC/uniontypes.c diff --git a/samples/LPC/array2.c b/samples/LPC/array2.c new file mode 100644 index 000000000..8a53b4c52 --- /dev/null +++ b/samples/LPC/array2.c @@ -0,0 +1,7 @@ +string* arr = ({ "a", "b", "c" }); +test() { + arr += ({ "d" }); + // should always allow subtracting 0 elements + arr -= ({ 0 }); + arr -= ({ "a" }); +} \ No newline at end of file diff --git a/samples/LPC/callOther3.c b/samples/LPC/callOther3.c new file mode 100644 index 000000000..20f5e959f --- /dev/null +++ b/samples/LPC/callOther3.c @@ -0,0 +1,7 @@ +test() { + /** @type {"object.c"*} */ + object *o = ({}); + + // call other on an array is legal in fluffos + o->query_number(); +} diff --git a/samples/LPC/closures.c b/samples/LPC/closures.c new file mode 100644 index 000000000..9eef2ee3c --- /dev/null +++ b/samples/LPC/closures.c @@ -0,0 +1,8 @@ +test() { + int *arr = ({1, 2, 3}); + int *i = filter(arr, (: $1 > 1 :)); +} + +private object *apply_custom_filter(object *obs, function f, object tp) { + return filter(obs, (: (*$(f))($1, $(tp)) :)) ; +} \ No newline at end of file diff --git a/samples/LPC/uniontypes.c b/samples/LPC/uniontypes.c new file mode 100644 index 000000000..3997f7e11 --- /dev/null +++ b/samples/LPC/uniontypes.c @@ -0,0 +1,5 @@ +// unionable types +public * testUnionable() { + tmp = 0; + return ({ 1, ({ "a" }) }); +}