├── irc
├── calcbot.ps1
├── package-lock.json
└── calcbot.js
├── Discord
├── calcbot.ps1
├── package.json
├── Bot description.txt
├── calcbot.js
└── package-lock.json
├── Procfile
├── C Version
├── parse.c
├── gentables.ps1
├── error.err
├── print.h
├── error.h
├── len str.h
├── aliases.gperf
├── builtins.gperf
├── error.c
├── len str.c
├── lex.h
├── parse.h
├── generrors.lua
├── types.h
├── print.c
├── builtins.h
├── aliases.h
├── types.c
├── lex.c
└── khash.h
├── Logos
├── calc Logo 2.png
├── calc Logo.png
├── Mini calc Logo.png
├── calc Logo Flat.png
├── calc_Logo_GitHub.png
├── calc Logo Flat.svg
├── Mini calc Logo.svg
└── calc Logo.svg
├── console
├── FiraMono.ttf
├── index.html
├── style.css
└── console.js
├── .gitignore
├── index.html
├── package.json
├── readme.md
├── calc
├── variable manipulation.js
├── calc.js
├── run.js
├── print.js
├── types.js
├── lex.js
├── run part.js
├── parse.js
├── standard library.js
└── help.js
├── CLI
└── calc.js
└── LICENSE.txt
/irc/calcbot.ps1:
--------------------------------------------------------------------------------
1 | node calcbot.js
--------------------------------------------------------------------------------
/Discord/calcbot.ps1:
--------------------------------------------------------------------------------
1 | node calcbot.js
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | worker: node Discord/calcbot.js
--------------------------------------------------------------------------------
/C Version/parse.c:
--------------------------------------------------------------------------------
1 | #include "len str.h"
2 | #include "parse.h"
--------------------------------------------------------------------------------
/Logos/calc Logo 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Camto/calc/HEAD/Logos/calc Logo 2.png
--------------------------------------------------------------------------------
/Logos/calc Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Camto/calc/HEAD/Logos/calc Logo.png
--------------------------------------------------------------------------------
/console/FiraMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Camto/calc/HEAD/console/FiraMono.ttf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Thumbs.db
2 | WIP Examples
3 | node_modules
4 | *.exe
5 | comprun.ps1
6 | main.c
--------------------------------------------------------------------------------
/Logos/Mini calc Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Camto/calc/HEAD/Logos/Mini calc Logo.png
--------------------------------------------------------------------------------
/Logos/calc Logo Flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Camto/calc/HEAD/Logos/calc Logo Flat.png
--------------------------------------------------------------------------------
/Logos/calc_Logo_GitHub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Camto/calc/HEAD/Logos/calc_Logo_GitHub.png
--------------------------------------------------------------------------------
/C Version/gentables.ps1:
--------------------------------------------------------------------------------
1 | $PSDefaultParameterValues["Out-File:Encoding"] = "utf8"
2 | gperf .\builtins.gperf -c -t > builtins.h
3 | gperf .\aliases.gperf -c -t > aliases.h
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Redirecting to console/
4 |
5 |
--------------------------------------------------------------------------------
/C Version/error.err:
--------------------------------------------------------------------------------
1 | lex_unclosed_str `Found " to start a string starting here, but none to finish it.`
2 |
3 | lex_dot `Found a single ".", did you mean to put the ".." operator or a number there?`
4 | lex_colon `Found a ":", did you mean to put the ":=" operator there?`
--------------------------------------------------------------------------------
/Discord/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calcbot",
3 | "version": "1.0.0",
4 | "description": "The calc= programming language bot.",
5 | "main": "calcbot.js",
6 | "author": "Benjamin Philippe Applegate",
7 | "license": "MIT",
8 | "dependencies": {
9 | "discord.js": "^12.2.0"
10 | }
11 | }
--------------------------------------------------------------------------------
/C Version/print.h:
--------------------------------------------------------------------------------
1 | #ifndef CALC_PRINT
2 | #define CALC_PRINT
3 |
4 | #include "len str.h"
5 | #include "types.h"
6 |
7 | Calc_Len_Str* calc_print(Calc_Stack* stack);
8 | Calc_Len_Str* calc_print_val(Calc_Val* val);
9 |
10 | void calc_debug_stack(Calc_Stack* stack);
11 | void calc_debug_val(Calc_Val* val);
12 |
13 | #endif
14 |
--------------------------------------------------------------------------------
/Discord/Bot description.txt:
--------------------------------------------------------------------------------
1 | I'm a simple calculator so you don't have to leave Discord for basic calculations! For some help, type "calc= help". I use a miniature functional concatenative programming language named calc= . Here's an example to give you a taste: "calc= fib = {n -> 0 1 {x y -> y x y +} n iter drop} ; 0 9 .. $fib map" gives the first ten fibonacci numbers.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calcbot",
3 | "version": "1.0.0",
4 | "description": "The calc= programming language bot.",
5 | "main": "Discord/calcbot.js",
6 | "author": "Benjamin Philippe Applegate",
7 | "license": "MIT",
8 | "dependencies": {
9 | "discord.js": "^12.2.0"
10 | },
11 | "scripts": {
12 | "start": "pushd console; npx http-server -p $PORT; popd"
13 | }
14 | }
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Click [here](https://camto.github.io/calc/console) to go to the calc= console, where you can try it out and get the documentation.
4 |
5 | Welcome to calc=, the stack language for chats! For a basic tutorial, type `calc= tut`. If you already know stack based programming, use `calc= adv_tut`.
6 |
7 | Demos:
8 | * Fibonacci: `calc= fib = {n -> 0 1 {x y -> y x y +} n iter drop} ; 0 9 .. $fib map`
9 | * Factorial: `calc= 1 5 .. $* 1 fold`
--------------------------------------------------------------------------------
/calc/variable manipulation.js:
--------------------------------------------------------------------------------
1 | function get_variable(name, scopes) {
2 | for(let cou = scopes.length - 1; cou >= 0; cou--) {
3 | if(scopes[cou][name]) {
4 | return scopes[cou][name];
5 | }
6 | }
7 | return undefined;
8 | }
9 |
10 | function set_variable(name, value, scopes) {
11 | for(let cou = scopes.length - 1; cou >= 0; cou--) {
12 | if(scopes[cou][name]) {
13 | scopes[cou][name] = value;
14 | return scopes[cou][name];
15 | }
16 | }
17 | return undefined;
18 | }
19 |
20 | module.exports = {get_variable, set_variable};
--------------------------------------------------------------------------------
/irc/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "requires": true,
3 | "lockfileVersion": 1,
4 | "dependencies": {
5 | "irc": {
6 | "version": "0.5.2",
7 | "resolved": "https://registry.npmjs.org/irc/-/irc-0.5.2.tgz",
8 | "integrity": "sha1-NxT0doNlqW0LL3dryRFmvrJGS7w=",
9 | "requires": {
10 | "irc-colors": "1.4.2"
11 | }
12 | },
13 | "irc-colors": {
14 | "version": "1.4.2",
15 | "resolved": "https://registry.npmjs.org/irc-colors/-/irc-colors-1.4.2.tgz",
16 | "integrity": "sha512-QZ1g4d9XTGKgBAp7lrltCetefqd3zfYs3SFQ4YyRSORORCmy/9EkU/r8LJrlSnaWc3Z+54EgHXBRlOHaCvpyHA=="
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CLI/calc.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var fs = require("fs");
4 | var calc = require("./../calc/calc");
5 |
6 | var args = process.argv.slice(2);
7 |
8 | // Running exprs directly from the command line can be added later.
9 | if(args.length >= 1) {
10 | var prog = fs.readFileSync(args[0]);
11 | var result;
12 | var result = (() => {
13 | try {
14 | return calc.print(calc.calc("calc= " + prog));
15 | } catch(err) {
16 | console.log(`Ran program
17 | ${prog}
18 | with error`);
19 | return calc.err_to_str(err);
20 | }
21 | })();
22 | console.log(result);
23 | } else {
24 | console.log("calc=Error: did not provide file to read.");
25 | }
--------------------------------------------------------------------------------
/console/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | calc=
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/calc/calc.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var lex = require("./lex");
4 | var parse = require("./parse");
5 | var run = require("./run");
6 | var print = require("./print");
7 |
8 | function calc(code_, max_time) {
9 | if(code_.substr(0, 5) != "calc=") {
10 | throw "Error: there is no \"calc=\".";
11 | }
12 | var code = code_.substr(5, code_.length);
13 | try {
14 | var tokens = lex(code);
15 | var ast = parse(tokens);
16 | return run(ast, max_time, calc);
17 | } catch(err) {
18 | throw "calc=" + err_to_str(err);
19 | }
20 | }
21 |
22 | var err_to_str = err => !(err instanceof Error)
23 | ? err
24 | : "\n" + err.stack.split("\n").slice(0, 2).join("\n\t");
25 |
26 | module.exports = {calc, print, err_to_str};
--------------------------------------------------------------------------------
/irc/calcbot.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var calc = require("./../calc/calc");
4 |
5 | var irc = require("irc");
6 |
7 | var config = {
8 | channels: ["#calc"],
9 | server: "irc.freenode.net",
10 | name: "calcbot"
11 | };
12 |
13 | var bot = new irc.Client(config.server, config.name, {
14 | channels: config.channels
15 | });
16 |
17 | bot.addListener("message", function(from, to, text, message) {
18 | if (from != "calcbot" && text.substring(0, 5) == "calc=") {
19 | bot.say(config.channels[0], (() => {
20 | try {
21 | return calc.print(calc.calc(text));
22 | } catch(err) {
23 | console.log(calc.err_to_str(err));
24 | return calc.err_to_str(err);
25 | }
26 | })().replace("\t", " "));
27 | }
28 | });
--------------------------------------------------------------------------------
/C Version/error.h:
--------------------------------------------------------------------------------
1 | #ifndef CALC_ERROR
2 | #define CALC_ERROR
3 |
4 | #include "len str.h"
5 |
6 | typedef Calc_Len_Str* Calc_Maybe_Error;
7 |
8 | typedef enum {calc_error, calc_result} Calc_Is_Error;
9 | #define Calc_Errorful(T) \
10 | struct { \
11 | Calc_Is_Error is_error; \
12 | union { \
13 | Calc_Len_Str* error; \
14 | T result; \
15 | } data; \
16 | }
17 |
18 | typedef struct {
19 | size_t start_cut;
20 | size_t end_cut;
21 | int line_count;
22 | } Calc_Error_Header_Info;
23 |
24 | Calc_Error_Header_Info calc_error_header_info(
25 | const Calc_Len_Str* prog,
26 | size_t pos
27 | );
28 |
29 | void calc_error_append_header(
30 | Calc_Len_Str* buf,
31 | const Calc_Len_Str* prog, size_t pos,
32 | size_t start_cut, size_t end_cut
33 | );
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/C Version/len str.h:
--------------------------------------------------------------------------------
1 | #ifndef CALC_LEN_STR
2 | #define CALC_LEN_STR
3 |
4 | #include
5 |
6 | #define Calc_Len_Str_Size(size) struct { \
7 | size_t len; \
8 | char chars[size]; \
9 | }
10 |
11 | typedef Calc_Len_Str_Size(1) Calc_Len_Str;
12 |
13 | const Calc_Len_Str empty_str;
14 |
15 | Calc_Len_Str* calc_to_len_str(const char* c_str);
16 | char* calc_from_len_str(const Calc_Len_Str* str);
17 |
18 | /* Calc_Len_Str* calc_len_str_slice(const Calc_Len_Str* str, size_t start, size_t len); */
19 | char* calc_from_len_str_slice(const Calc_Len_Str* str, size_t start, size_t len);
20 |
21 | Calc_Len_Str* calc_len_str_copy(const Calc_Len_Str* str);
22 |
23 | Calc_Len_Str* calc_len_str_prealloc(size_t len);
24 | void calc_len_str_append(Calc_Len_Str* str, const Calc_Len_Str* end);
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/calc/run.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var run_part = require("./run part");
4 | var standard_library = require("./standard library");
5 |
6 | function run(ast, max_time = Infinity, calc) {
7 | var stack = [];
8 |
9 | var end_time = (new Date).getTime() + max_time;
10 |
11 | var operators = standard_library.operators(stack);
12 | var built_ins = standard_library.built_ins(stack, calc, operators, end_time);
13 |
14 | var variables = {};
15 | for(let cou = 0; cou < ast.variables.length; cou++) {
16 | run_part.run_block(ast.variables[cou].data, stack, [variables], built_ins, operators, end_time);
17 | variables[ast.variables[cou].name] = stack.pop();
18 | }
19 |
20 | run_part.run_block(ast.data, stack, [variables], built_ins, operators, end_time);
21 |
22 | return stack;
23 | }
24 |
25 | module.exports = run;
--------------------------------------------------------------------------------
/console/style.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: FiraMono;
3 | src: url(FiraMono.ttf);
4 | }
5 |
6 | * {
7 | font-family: FiraMono, Courier;
8 | font-size: 16px;
9 | color: white;
10 | }
11 |
12 | body {
13 | margin: 0px;
14 | }
15 |
16 | html, body, #console {
17 | height: 100%;
18 | }
19 |
20 | #console {
21 | display: flex;
22 | flex-direction: column;
23 | }
24 |
25 | #calcbox {
26 | display: flex;
27 | background: black;
28 | border: none;
29 | outline: none;
30 | border-top: 1px solid white;
31 | }
32 |
33 | #calc-header {
34 | float: left;
35 | padding: 2px;
36 | padding-right: 0px;
37 | }
38 |
39 | #calc {
40 | resize: none;
41 | background: black;
42 | border: none;
43 | outline: none;
44 | padding: 2px;
45 | padding-left: 0px;
46 | flex-grow: 1;
47 | }
48 |
49 | #log {
50 | padding: 2px;
51 | background: #001D32;
52 | flex: 1;
53 | position: relative;
54 | overflow: auto;
55 | overflow-wrap: break-word;
56 | }
--------------------------------------------------------------------------------
/Discord/calcbot.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var calc = require("./../calc/calc");
4 | var discord = require("discord.js");
5 |
6 | var client = new discord.Client();
7 |
8 | client.on("ready", () => {
9 | console.log(`${client.user.tag} is logged in!`);
10 | client.user.setActivity("calc= h");
11 | });
12 |
13 | client.on("message", msg => {
14 | if(msg.content == "calcbotact") {
15 | client.user.setActivity("calc= h");
16 | console.log('Reset activity to "calc= h".');
17 | }
18 |
19 | if(
20 | !msg.author.bot &&
21 | msg.content.substring(0, 5) == "calc="
22 | ) {
23 | console.log("Got request.")
24 |
25 | var result = (() => {
26 | try {
27 | return calc.print(calc.calc(msg.content), 10000);
28 | } catch(err) {
29 | console.log(`Ran program
30 | ${msg.content}
31 | with error
32 | ${calc.err_to_str(err)}`);
33 | return calc.err_to_str(err);
34 | }
35 | })();
36 |
37 | msg.channel.send(result);
38 | }
39 | });
40 |
41 | client.login(process.env.TOKEN);
--------------------------------------------------------------------------------
/C Version/aliases.gperf:
--------------------------------------------------------------------------------
1 | %{
2 | #ifndef CALC_ALIASES
3 | #define CALC_ALIASES
4 |
5 | #include
6 | #include
7 |
8 | #include "len str.h"
9 |
10 | static const Calc_Len_Str calc_type_main_alias = {4, 't', 'y', 'p', 'e'};
11 | static const Calc_Len_Str calc_dup_main_alias = {3, 'd', 'u', 'p'};
12 | static const Calc_Len_Str calc_drop_main_alias = {4, 'd', 'r', 'o', 'p'};
13 | %}
14 | %define lookup-function-name get_main_alias
15 | %define hash-function-name hash_aliases
16 | struct Calc_Alias {char* name; const Calc_Len_Str* main_alias;};
17 | %%
18 | type, &calc_type_main_alias
19 | typeof, &calc_type_main_alias
20 | instance, &calc_type_main_alias
21 | instanceof, &calc_type_main_alias
22 | #
23 | dup, &calc_dup_main_alias
24 | duplicate, &calc_dup_main_alias
25 | #
26 | drop, &calc_drop_main_alias
27 | stack_pop, &calc_drop_main_alias
28 | %%
29 | #undef TOTAL_KEYWORDS
30 | #undef MIN_WORD_LENGTH
31 | #undef MAX_WORD_LENGTH
32 | #undef MIN_HASH_VALUE
33 | #undef MAX_HASH_VALUE
34 |
35 | #endif
--------------------------------------------------------------------------------
/calc/print.js:
--------------------------------------------------------------------------------
1 | var types = require("./types");
2 |
3 | module.exports = function print(value) {
4 | if(value instanceof Array) {
5 | var result = "calc=";
6 | for(let cou = 0; cou < value.length; cou++) {
7 | result += print(value[cou]);
8 | if(cou < value.length - 1) {
9 | result += " ";
10 | }
11 | }
12 | return result;
13 | } else {
14 |
15 | switch(value.type) {
16 | case types.str:
17 | case types.sym:
18 | case types.op:
19 | return value.data;
20 | break;
21 | case types.num:
22 | return Math.round(value.data * 100000) / 100000;
23 | case types.list:
24 | var list = "[";
25 | for(let cou = 0; cou < value.data.length; cou++) {
26 | list += print(value.data[cou]);
27 | if(cou < value.data.length - 1) {
28 | list += ", ";
29 | }
30 | }
31 | list += "]";
32 | return list;
33 | break;
34 | case types.func:
35 | return `{${value.args.join(" ")} -> }`;
36 | break;
37 | }
38 |
39 | }
40 | }
--------------------------------------------------------------------------------
/C Version/builtins.gperf:
--------------------------------------------------------------------------------
1 | %{
2 | #ifndef CALC_BUILTINS
3 | #define CALC_BUILTINS
4 |
5 | #include
6 | #include
7 |
8 | #include "types.h"
9 |
10 | #define __builtin(name) void name( \
11 | Calc_Stack* stack, \
12 | Calc_Scopes* scopes, \
13 | void* custom_builtins, \
14 | time_t end_time \
15 | )
16 |
17 | __builtin(calc_builtin_type) {
18 | Calc_Val* val = calc_pop(stack);
19 | calc_push(stack, calc_new_str(calc_len_str_copy(calc_type_to_str(val->type))));
20 | calc_lose_ref(val);
21 | }
22 |
23 | __builtin(calc_builtin_dup) {
24 | Calc_Val* val = calc_peek(stack);
25 | calc_gain_ref(val);
26 | calc_push(stack, val);
27 | }
28 |
29 | __builtin(calc_builtin_drop) {
30 | calc_lose_ref(calc_pop(stack));
31 | }
32 | %}
33 | %define lookup-function-name get_builtin
34 | %define hash-function-name hash_builtins
35 | struct Calc_Lookup_Builtin {char* name; Calc_Builtin builtin;};
36 | %%
37 | type, calc_builtin_type
38 | dup, calc_builtin_dup
39 | drop, calc_builtin_drop
40 | %%
41 | #undef TOTAL_KEYWORDS
42 | #undef MIN_WORD_LENGTH
43 | #undef MAX_WORD_LENGTH
44 | #undef MIN_HASH_VALUE
45 | #undef MAX_HASH_VALUE
46 |
47 | #endif
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Benjamin Philippe Applegate
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/C Version/error.c:
--------------------------------------------------------------------------------
1 | #include "error.h"
2 |
3 | #include
4 |
5 | Calc_Error_Header_Info calc_error_header_info(
6 | const Calc_Len_Str* prog,
7 | size_t pos
8 | ) {
9 | size_t i;
10 | size_t start_cut = 0;
11 | size_t end_cut = prog->len;
12 | int line_count = 0;
13 | Calc_Error_Header_Info info;
14 |
15 | for(i = 0; i < pos; i++)
16 | if(prog->chars[i] == '\n') {
17 | line_count++;
18 | start_cut = i + 1;
19 | }
20 |
21 | for(i = pos; i < prog->len; i++)
22 | if(prog->chars[i] == '\n') {
23 | end_cut = i;
24 | break;
25 | }
26 |
27 | if(pos - start_cut > 10) start_cut = pos - 10;
28 | if(end_cut - pos > 11) end_cut = pos + 11;
29 |
30 | info.start_cut = start_cut;
31 | info.end_cut = end_cut;
32 | info.line_count = line_count;
33 | return info;
34 | }
35 |
36 | void calc_error_append_header(
37 | Calc_Len_Str* buf,
38 | const Calc_Len_Str* prog, size_t pos,
39 | size_t start_cut, size_t end_cut
40 | ) {
41 | size_t i;
42 | size_t cut_len = end_cut - start_cut;
43 |
44 | memcpy(&buf->chars[buf->len], &prog->chars[start_cut], cut_len);
45 | buf->len += cut_len;
46 | buf->chars[buf->len] = '\n';
47 | buf->len++;
48 | for(i = 0; i < pos - start_cut; i++) {
49 | buf->chars[buf->len] = ' ';
50 | buf->len++;
51 | }
52 | buf->chars[buf->len] = '^';
53 | buf->len++;
54 | for(i = 0; i < end_cut - pos - 1; i++) {
55 | buf->chars[buf->len] = ' ';
56 | buf->len++;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/C Version/len str.c:
--------------------------------------------------------------------------------
1 | #include "len str.h"
2 |
3 | #include
4 | #include
5 |
6 | const Calc_Len_Str empty_str = {0};
7 |
8 | Calc_Len_Str* calc_to_len_str(const char* c_str) {
9 | size_t len = (size_t) strlen(c_str);
10 | Calc_Len_Str* str = malloc(sizeof(Calc_Len_Str) + sizeof(char) * len);
11 | str->len = len;
12 | memcpy(&str->chars, c_str, len);
13 | return str;
14 | }
15 |
16 | char* calc_from_len_str(const Calc_Len_Str* str) {
17 | size_t len = str->len;
18 | char* c_str = malloc(sizeof(char) * (len + 1));
19 | memcpy(c_str, &str->chars, len);
20 | c_str[len] = '\0';
21 | return c_str;
22 | }
23 |
24 | char* calc_from_len_str_slice(const Calc_Len_Str* str, size_t start, size_t len) {
25 | char* c_str = malloc(sizeof(char) * (len + 1));
26 | memcpy(c_str, &str->chars[start], len);
27 | c_str[len] = '\0';
28 | return c_str;
29 | }
30 |
31 | Calc_Len_Str* calc_len_str_copy(const Calc_Len_Str* str) {
32 | size_t len = str->len;
33 | Calc_Len_Str* copy = malloc(sizeof(Calc_Len_Str) + sizeof(char) * len);
34 | copy->len = len;
35 | memcpy(©->chars, &str->chars, len);
36 | return copy;
37 | }
38 |
39 | Calc_Len_Str* calc_len_str_prealloc(size_t len) {
40 | Calc_Len_Str* str = malloc(sizeof(Calc_Len_Str) + sizeof(char) * len);
41 | str->len = 0;
42 | return str;
43 | }
44 |
45 | void calc_len_str_append(Calc_Len_Str* str, const Calc_Len_Str* end) {
46 | memcpy(&str->chars[str->len], &end->chars, end->len);
47 | str->len += end->len;
48 | }
49 |
--------------------------------------------------------------------------------
/C Version/lex.h:
--------------------------------------------------------------------------------
1 | #ifndef CALC_LEX
2 | #define CALC_LEX
3 |
4 | #include
5 |
6 | #include "len str.h"
7 |
8 | typedef enum {
9 | calc_num_token, calc_str_token, calc_op_token, calc_sym_token
10 | } Calc_Token_Type;
11 |
12 | typedef enum {
13 | /* Normal operators. */
14 | calc_add, calc_sub, calc_mul, calc_div, calc_pow, calc_mod,
15 | calc_to,
16 | calc_and, calc_or, calc_not,
17 | calc_eq_, calc_neq, calc_lt, calc_gt, calc_lte, calc_gte,
18 | /* Context operators (only for parsing). */
19 | calc_refof,
20 | calc_list_start, calc_list_end, calc_list_sep,
21 | calc_func_start, calc_func_end, calc_func_arrow,
22 | calc_var_decl, calc_var_sep
23 | } Calc_Op;
24 |
25 | typedef struct {
26 | Calc_Token_Type type;
27 | union {
28 | Calc_Len_Str* sym;
29 | double num;
30 | Calc_Len_Str* str;
31 | Calc_Op op;
32 | } data;
33 | } Calc_Token;
34 |
35 | typedef struct {
36 | size_t len;
37 | size_t cap;
38 | Calc_Token* tokens;
39 | } Calc_Tokens;
40 |
41 | Calc_Tokens calc_lex(const Calc_Len_Str* prog);
42 |
43 | void calc_expect_num(
44 | Calc_Tokens* tokens,
45 | const Calc_Len_Str* prog,
46 | size_t* pos
47 | );
48 | int calc_expect_str(
49 | Calc_Tokens* tokens,
50 | const Calc_Len_Str* prog,
51 | size_t* pos
52 | );
53 | int calc_expect_op(
54 | Calc_Tokens* tokens,
55 | const Calc_Len_Str* prog,
56 | size_t* pos
57 | );
58 | void calc_expect_sym(
59 | Calc_Tokens* tokens,
60 | const Calc_Len_Str* prog,
61 | size_t* pos
62 | );
63 |
64 | void calc_free_tokens(Calc_Tokens tokens);
65 |
66 | void calc_append_token(Calc_Tokens* tokens, Calc_Token token);
67 |
68 | bool calc_is_op_normal(Calc_Op op);
69 | const Calc_Len_Str* calc_op_to_str(Calc_Op op);
70 |
71 | #endif
72 |
--------------------------------------------------------------------------------
/C Version/parse.h:
--------------------------------------------------------------------------------
1 | #ifndef CALC_PARSE
2 | #define CALC_PARSE
3 |
4 | #include "lex.h"
5 |
6 | typedef struct Calc_Ast_Func Calc_Ast_Func;
7 | typedef Calc_Ast_Func Calc_Ast;
8 | typedef struct Calc_Ast_Var Calc_Ast_Var;
9 | typedef struct Calc_Ast_Expr Calc_Ast_Expr;
10 | typedef struct Calc_Ast_Instr Calc_Ast_Instr;
11 | typedef struct Calc_Ast_List Calc_Ast_List;
12 | typedef struct Calc_Ast_Refof Calc_Ast_Refof;
13 |
14 | /* The whole program is a func. */
15 | struct Calc_Ast_Func {
16 | size_t vars_len;
17 | Calc_Ast_Var* vars;
18 | Calc_Ast_Expr* body;
19 | };
20 |
21 | struct Calc_Ast_Var {
22 | Calc_Len_Str* name;
23 | Calc_Ast_Expr* def;
24 | };
25 |
26 | struct Calc_Ast_Expr {
27 | size_t len;
28 | Calc_Ast_Instr** instrs;
29 | };
30 |
31 | struct Calc_Ast_Instr {
32 | Calc_Ast_Instr_Type type;
33 | union {
34 | double num;
35 | Calc_Len_Str* str;
36 | /* At this point normal operators are turned into symbols. */
37 | Calc_Len_Str* sym;
38 | Calc_Ast_Func* func;
39 | Calc_Ast_List* list;
40 | Calc_Ast_Instr* refof;
41 | } data;
42 | };
43 |
44 | struct Calc_Ast_List {
45 | size_t len;
46 | Calc_Ast_Expr** items;
47 | };
48 |
49 | Calc_Ast_Func calc_parse(const Calc_Tokens tokens);
50 |
51 | Calc_Ast_Func calc_parse_prog(const Calc_Tokens* tokens size_t* pos);
52 | Calc_Ast_Var calc_parse_var(const Calc_Tokens* tokens size_t* pos);
53 | Calc_Ast_Expr calc_parse_expr(const Calc_Tokens* tokens size_t* pos);
54 | Calc_Ast_Instr calc_parse_instr(const Calc_Tokens* tokens size_t* pos);
55 | Calc_Ast_Func calc_parse_func(const Calc_Tokens* tokens size_t* pos);
56 | Calc_Ast_List calc_parse_list(const Calc_Tokens* tokens size_t* pos);
57 | Calc_Ast_Instr calc_parse_refof(const Calc_Tokens* tokens size_t* pos);
58 |
59 | #endif
--------------------------------------------------------------------------------
/C Version/generrors.lua:
--------------------------------------------------------------------------------
1 | require "pl"
2 |
3 | local function skip_ws(prog, i)
4 | local ws = prog:sub(i):match"[ \n]*"
5 | return i + #ws
6 | end
7 |
8 | local function parse_name(prog, i)
9 | local name = prog:sub(i):match"[%w_]+"
10 | return name, i + #name
11 | end
12 |
13 | local str, insert = false, true
14 |
15 | local function parse_str(prog, i)
16 | local str_ = prog:sub(i):match"`[^`]*`":sub(2, -2)
17 |
18 | local parsed_str = List{}
19 | local current_state = str
20 | for section in str_:gmatch"[^\\]+" do
21 | parsed_str:append{type = current_state, data = section}
22 | current_state = not current_state
23 | end
24 |
25 | return parsed_str, i + #str_ + 2
26 | end
27 |
28 | local function parse_prog(prog)
29 | local errors = List{}
30 |
31 | local i = 1
32 | while i <= #prog do
33 | local name
34 | local str_
35 | i = skip_ws(prog, i)
36 | name, i = parse_name(prog, i)
37 | i = skip_ws(prog, i)
38 | str_, i = parse_str(prog, i)
39 | i = skip_ws(prog, i)
40 | errors:append{name = name, str = str_}
41 | end
42 |
43 | return errors
44 | end
45 |
46 | local function to_c_char(char)
47 | if char == "'" then return "'\\''"
48 | elseif char == "\n" then return "'\\n'"
49 | elseif char == "\\" then return "'\\\\'"
50 | else return "'" .. char .. "'" end
51 | end
52 |
53 | local function error_to_func(error)
54 | local name = error.name
55 | local str = error.str[1].data
56 |
57 | return {
58 | "static const Calc_Len_Str_Size(" .. #str .. ") calc_error_" .. name ..
59 | "_str = {" .. #str .. ", " .. List(str):map(to_c_char):join", " .. "};",
60 |
61 | "Calc_Len_Str* calc_error_" .. name .. [[(const Calc_Len_Str* prog, size_t pos) {
62 | Calc_Len_Str* buf;
63 | Calc_Error_Header_Info info = Calc_Error_Header_Info(prog, pos);
64 | buf = calc_len_str_prealloc(
65 | (info.start_cut - info.end_cut) * 2 + 3 + ]] .. #str .. [[
66 |
67 | );
68 | calc_error_append_header(
69 | buf,
70 | prog, pos,
71 | info.start_cut, info.end_cut
72 | );
73 | calc_len_str_append(buf, calc_two_newlines);
74 | calc_len_str_append(buf, calc_error_]] .. name .. [[_str);
75 |
76 | return buf;
77 | }]],
78 |
79 | "Calc_Len_Str* calc_error_" .. name .. "(const Calc_Len_Str* prog, size_t pos);"
80 | }
81 | end
82 |
83 | local error_file = io.open("error.err", "r")
84 | local prog = error_file:read"*a"
85 | error_file:close()
86 |
87 | errors = parse_prog(prog)
88 |
89 | pretty.dump(errors:map(error_to_func))
--------------------------------------------------------------------------------
/calc/types.js:
--------------------------------------------------------------------------------
1 | var types = {
2 | num: 0, str: 1, list: 2,
3 | func: 3, sym: 4, op: 5
4 | };
5 |
6 | var new_value = {
7 | new_num: num => ({data: num, type: types.num}),
8 | new_bool: bool => ({data: bool | 0, type: types.num}),
9 | new_str: str => ({data: str, type: types.str}),
10 | new_list: list => ({data: list, type: types.list}),
11 | new_sym: sym => ({data: sym, type: types.sym}),
12 | new_op: op => ({data: op, type: types.op})
13 | };
14 |
15 | var is_type = {
16 | is_num: val => val.type == types.num,
17 | is_str: val => val.type == types.str,
18 | is_list: val => val.type == types.list,
19 | is_func: val => val.type == types.func,
20 | is_sym: val => val.type == types.sym,
21 | is_op: val => val.type == types.op,
22 | is_list_like: val => is_type.is_list(val) || is_type.is_str(val)
23 | };
24 |
25 | function type_to_str(type) {
26 | switch(type) {
27 | case types.num:
28 | return "number";
29 | case types.str:
30 | return "string";
31 | case types.list:
32 | return "list";
33 | case types.func:
34 | return "function";
35 | case types.sym:
36 | return "symbol";
37 | case types.op:
38 | return "operator";
39 | }
40 | }
41 |
42 | function to_bool(val) {
43 | if(val.is_ref) {
44 | return true;
45 | }
46 | switch(val.type) {
47 | case types.num:
48 | case types.str:
49 | return Boolean(val.data);
50 | break;
51 | case types.func:
52 | case types.sym:
53 | case types.op:
54 | return true;
55 | break;
56 | case types.list:
57 | return Boolean(val.data.length);
58 | break;
59 | }
60 | return false;
61 | }
62 |
63 | function eq(left, right) {
64 | if(
65 | is_type.is_num(left) && is_type.is_num(right) ||
66 | is_type.is_str(left) && is_type.is_str(right)
67 | ) {
68 | return left.data == right.data;
69 | } else if(is_type.is_list(left) && is_type.is_list(right)) {
70 | if(left.data.length != right.data.length) {
71 | return false;
72 | }
73 | for(var cou = 0; cou < left.data.length; cou++) {
74 | if(!eq(left.data[cou], right.data[cou])) {
75 | return false;
76 | }
77 | }
78 | return true;
79 | } else {
80 | return false;
81 | }
82 | }
83 |
84 | function cmp(left, right, comparator) {
85 | if(is_type.is_num(left) && is_type.is_num(right)) {
86 | return comparator(left.data, right.data);
87 | } else if(
88 | is_type.is_list_like(left) && is_type.is_list_like(right)
89 | ) {
90 | return comparator(left.data.length, right.data.length);
91 | }
92 | return false;
93 | }
94 |
95 | module.exports = {
96 | ...types, ...new_value, ...is_type,
97 | type_to_str, to_bool,
98 | eq, cmp
99 | };
--------------------------------------------------------------------------------
/console/console.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var past = [""];
4 | var travel = 2;
5 |
6 | $(function() {
7 | $("#log").append(escape_input(calc.print(calc.calc("calc= h", 10000))) + "
");
8 | past.push("h");
9 | if(location.search.substring(6) == "") {
10 | history.replaceState("", "", "?calc=h");
11 | } else {
12 | var prog = decodeURIComponent(location.search.substring(6));
13 | if(prog != "h") {
14 | $("#log").append("calc= " + escape_input(prog) + "
");
15 | var result;
16 | try {
17 | result = calc.print(calc.calc("calc= " + prog, 10000));
18 | } catch(err) {
19 | result = calc.err_to_str(err);
20 | }
21 | $("#log").append(escape_input(result) + "
");
22 | past.push(decodeURIComponent(location.search.substring(6)));
23 | travel++;
24 | }
25 | }
26 |
27 | $("#calc").keyup(function(key) {
28 | switch(key.which) {
29 | case 13:
30 | $(this).val($(this).val().replace(/[\n\r]/g, ""));
31 | var result = "";
32 | try {
33 | result = calc.print(calc.calc("calc= " + $(this).val(), 10000));
34 | } catch(err) {
35 | result = calc.err_to_str(err);
36 | }
37 | past.push($(this).val().replace(/[\n\r]/g, ""));
38 | travel = past.length;
39 | history.replaceState("", "", "?calc=" + encodeURIComponent($(this).val().replace(/[\n\r]/g, "")));
40 |
41 | $("#log").append("calc= " + escape_input($(this).val()) + "
");
42 | $("#log").append(escape_input(result) + "
");
43 | $(this).val("");
44 | $("#log").scrollTop($("#log")[0].scrollHeight);
45 | break;
46 | case 38:
47 | travel--;
48 | if(travel <= 0) {
49 | travel = 0;
50 | }
51 | $(this).val(past[travel]);
52 | var length = $(this).val().length * 2;
53 | setTimeout(() => this.setSelectionRange(length, length), 1);
54 | break;
55 | case 40:
56 | travel++;
57 | if(travel > past.length - 1) {
58 | travel = past.length;
59 | $(this).val("");
60 | setTimeout(() => this.setSelectionRange(6, 6), 1);
61 | } else {
62 | $(this).val(past[travel]);
63 | var length = $(this).val().length * 2;
64 | setTimeout(() => this.setSelectionRange(length, length), 1);
65 | }
66 | break;
67 | }
68 | });
69 |
70 | $("#calc").keydown(function() {
71 | $(this).val($(this).val().replace(/[\n\r]/g, ""));
72 | });
73 | });
74 |
75 | function escape_input(string) {
76 | return string
77 | .replace(/&/g, "&")
78 | .replace(//g, ">")
80 | .replace(/"/g, """)
81 | .replace(/'/g, "'")
82 | .replace(/\t/g, " ")
83 | .replace(/\n/g, "
");
84 | }
--------------------------------------------------------------------------------
/C Version/types.h:
--------------------------------------------------------------------------------
1 | #ifndef CALC_TYPES
2 | #define CALC_TYPES
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "khash.h"
9 |
10 | #include "len str.h"
11 |
12 | typedef enum {
13 | calc_num, calc_str, calc_list,
14 | calc_func, calc_ref, calc_op
15 | } Calc_Type;
16 |
17 | #include "lex.h" /* Remove later. */
18 |
19 | typedef struct Calc_Val_List Calc_Val_List;
20 | typedef Calc_Val_List Calc_Block;
21 | typedef struct Calc_Func Calc_Func;
22 | typedef struct Calc_Ref Calc_Ref;
23 |
24 | typedef struct {
25 | Calc_Type type;
26 | union {
27 | double num;
28 | Calc_Len_Str* str;
29 | Calc_Val_List* list;
30 | Calc_Func* func;
31 | Calc_Ref* ref;
32 | Calc_Op op;
33 | } data;
34 | unsigned int refs;
35 | } Calc_Val;
36 |
37 | #define CALC_START_CAP 128
38 |
39 | typedef struct {
40 | size_t len;
41 | size_t cap;
42 | Calc_Val** vals;
43 | } Calc_Stack;
44 |
45 | KHASH_MAP_INIT_STR(Calc_Val_Hash, Calc_Val)
46 | typedef khash_t(Calc_Val_Hash) Calc_Scope;
47 |
48 | typedef struct {
49 | size_t len;
50 | Calc_Scope** scopes;
51 | } Calc_Scopes;
52 |
53 | struct Calc_Val_List {
54 | size_t len;
55 | Calc_Val* vals[1];
56 | };
57 |
58 | struct Calc_Func {
59 | struct {
60 | size_t len;
61 | Calc_Len_Str** args;
62 | } args;
63 | struct {
64 | size_t len;
65 | Calc_Scope** vars;
66 | } vars;
67 | Calc_Scopes scopes;
68 | Calc_Block* body;
69 | };
70 |
71 | struct Calc_Ref {
72 | Calc_Len_Str* sym;
73 | Calc_Scopes scopes;
74 | };
75 |
76 | typedef void (*Calc_Builtin)(Calc_Stack*, Calc_Scopes*, void*, time_t);
77 |
78 | #include "stdlib.h"
79 |
80 | Calc_Val* calc_new_num(double num);
81 | Calc_Val* calc_new_bool(bool bool_);
82 | Calc_Val* calc_new_str(Calc_Len_Str* str);
83 | Calc_Val* calc_new_ref(Calc_Len_Str* ref, Calc_Scopes scopes);
84 | Calc_Val* calc_new_op(Calc_Op op);
85 |
86 | bool calc_is_num(Calc_Val* val);
87 | bool calc_is_str(Calc_Val* val);
88 | bool calc_is_list(Calc_Val* val);
89 | bool calc_is_func(Calc_Val* val);
90 | bool calc_is_ref(Calc_Val* val);
91 | bool calc_is_op(Calc_Val* val);
92 | bool calc_is_list_like(Calc_Val* val);
93 |
94 | const Calc_Len_Str* calc_type_to_str(Calc_Type type);
95 |
96 | bool calc_val_to_bool(Calc_Val* val);
97 |
98 | bool calc_dbl_eq(double n, double m);
99 | bool calc_eq(Calc_Val* v, Calc_Val* u);
100 | bool calc_cmp(Calc_Val* v, Calc_Val* u, bool comp(double, double));
101 |
102 | void calc_gain_ref(Calc_Val* val);
103 | void calc_lose_ref(Calc_Val* val);
104 |
105 | Calc_Stack calc_new_stack(size_t start_cap);
106 | void calc_free_stack(Calc_Stack* stack);
107 |
108 | void calc_push(Calc_Stack* stack, Calc_Val* val);
109 | Calc_Val* calc_pop(Calc_Stack* stack);
110 | Calc_Val* calc_peek(Calc_Stack* stack);
111 |
112 | #endif
113 |
--------------------------------------------------------------------------------
/calc/lex.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var types = require("./types");
4 |
5 | function lex(code) {
6 | var pointer = 0;
7 | var tokens = [];
8 |
9 | var expect = {
10 |
11 | sym() {
12 | var end = pointer + 1;
13 | while(/[A-Za-z_0-9]/.test(code[end]) && end < code.length) {
14 | end++;
15 | }
16 | var sym = code.substr(pointer, end - pointer);
17 | pointer = end;
18 | return types.new_sym(sym);
19 | },
20 |
21 | num() {
22 | var end = pointer + 1;
23 | while(/[0-9]/.test(code[end]) && end < code.length) {
24 | end++;
25 | }
26 | if(code[end] == "." && code[end + 1] != ".") {
27 | end++;
28 | while(/[0-9]/.test(code[end]) && end < code.length) {
29 | end++;
30 | }
31 | }
32 | var num = code.substr(pointer, end - pointer);
33 | pointer = end;
34 | return types.new_num(parseFloat(num));
35 | },
36 |
37 | str() {
38 | pointer++;
39 |
40 | var str = "";
41 | var escaped = false;
42 | while((code[pointer] != '"' || escaped) && pointer < code.length) {
43 | if(!escaped) {
44 | if(code[pointer] != "\\") {
45 | str += code[pointer];
46 | } else {
47 | escaped = true;
48 | }
49 | } else {
50 | escaped = false;
51 | switch(code[pointer]) {
52 | case "n":
53 | str += "\n";
54 | break;
55 | case "t":
56 | str += "\t";
57 | break;
58 | default:
59 | str += code[pointer];
60 | break;
61 | }
62 | }
63 | pointer++;
64 | }
65 |
66 | if(code[pointer] != '"') {
67 | throw 'Error: found " to start a string, but none to finish it.';
68 | }
69 |
70 | pointer++;
71 | return types.new_str(str);
72 | },
73 |
74 | char() {
75 | pointer += 2;
76 | if(code[pointer - 1] == "\\") {
77 | pointer++;
78 | switch(code[pointer - 1]) {
79 | case "n":
80 | return types.new_str("\n");
81 | case "t":
82 | return types.new_str("\t");
83 | default:
84 | return types.new_str(code[pointer - 1]);
85 | }
86 | }
87 | return types.new_str(code[pointer - 1]);
88 | },
89 |
90 | op() {
91 | var end = pointer;
92 | switch(code[end]) {
93 | case "-":
94 | if(code[end + 1] == ">") {end++;}
95 | break;
96 | case ".":
97 | if(code[end + 1] == ".") {end++;}
98 | break;
99 | case "<":
100 | case ">":
101 | case "!":
102 | if(code[end + 1] == "=") {end++;}
103 | break;
104 | }
105 | end++;
106 | var op = code.substr(pointer, end - pointer);
107 | pointer = end;
108 | return types.new_op(op);
109 | }
110 |
111 | };
112 |
113 | while(pointer < code.length) {
114 | if(/[A-Za-z_]/.test(code[pointer])) {
115 | tokens.push(expect.sym());
116 | } else if(/\d/.test(code[pointer])) {
117 | tokens.push(expect.num());
118 | } else if(code[pointer] == "-") {
119 | if(/\d/.test(code[pointer + 1])) {
120 | tokens.push(expect.num());
121 | } else {
122 | tokens.push(expect.op());
123 | }
124 | } else if(code[pointer] == '"') {
125 | tokens.push(expect.str());
126 | } else if(code[pointer] == "'") {
127 | tokens.push(expect.char());
128 | } else if(/\[|,|\]|{|}|\$|;|\+|\*|\/|\^|%|\.|=|<|>|&|\||!/.test(code[pointer])) {
129 | tokens.push(expect.op());
130 | } else {
131 | pointer++;
132 | }
133 | }
134 |
135 | return tokens;
136 | }
137 |
138 | module.exports = lex;
--------------------------------------------------------------------------------
/Logos/calc Logo Flat.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
101 |
--------------------------------------------------------------------------------
/Logos/Mini calc Logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
100 |
--------------------------------------------------------------------------------
/Logos/calc Logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
108 |
--------------------------------------------------------------------------------
/Discord/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calcbot",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@discordjs/collection": {
8 | "version": "0.1.5",
9 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.5.tgz",
10 | "integrity": "sha512-CU1q0UXQUpFNzNB7gufgoisDHP7n+T3tkqTsp3MNUkVJ5+hS3BCvME8uCXAUFlz+6T2FbTCu75A+yQ7HMKqRKw=="
11 | },
12 | "@discordjs/form-data": {
13 | "version": "3.0.1",
14 | "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
15 | "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
16 | "requires": {
17 | "asynckit": "^0.4.0",
18 | "combined-stream": "^1.0.8",
19 | "mime-types": "^2.1.12"
20 | }
21 | },
22 | "abort-controller": {
23 | "version": "3.0.0",
24 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
25 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
26 | "requires": {
27 | "event-target-shim": "^5.0.0"
28 | }
29 | },
30 | "asynckit": {
31 | "version": "0.4.0",
32 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
33 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
34 | },
35 | "combined-stream": {
36 | "version": "1.0.8",
37 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
38 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
39 | "requires": {
40 | "delayed-stream": "~1.0.0"
41 | }
42 | },
43 | "delayed-stream": {
44 | "version": "1.0.0",
45 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
46 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
47 | },
48 | "discord.js": {
49 | "version": "12.2.0",
50 | "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.2.0.tgz",
51 | "integrity": "sha512-Ueb/0SOsxXyqwvwFYFe0msMrGqH1OMqpp2Dpbplnlr4MzcRrFWwsBM9gKNZXPVBHWUKiQkwU8AihXBXIvTTSvg==",
52 | "requires": {
53 | "@discordjs/collection": "^0.1.5",
54 | "@discordjs/form-data": "^3.0.1",
55 | "abort-controller": "^3.0.0",
56 | "node-fetch": "^2.6.0",
57 | "prism-media": "^1.2.0",
58 | "setimmediate": "^1.0.5",
59 | "tweetnacl": "^1.0.3",
60 | "ws": "^7.2.1"
61 | }
62 | },
63 | "event-target-shim": {
64 | "version": "5.0.1",
65 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
66 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
67 | },
68 | "mime-db": {
69 | "version": "1.44.0",
70 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
71 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
72 | },
73 | "mime-types": {
74 | "version": "2.1.27",
75 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
76 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
77 | "requires": {
78 | "mime-db": "1.44.0"
79 | }
80 | },
81 | "node-fetch": {
82 | "version": "2.6.1",
83 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
84 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
85 | },
86 | "prism-media": {
87 | "version": "1.2.1",
88 | "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.1.tgz",
89 | "integrity": "sha512-R3EbKwJiYlTvGwcG1DpUt+06DsxOGS5W4AMEHT7oVOjG93MjpdhGX1whHyjnqknylLMupKAsKMEXcTNRbPe6Vw=="
90 | },
91 | "setimmediate": {
92 | "version": "1.0.5",
93 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
94 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
95 | },
96 | "tweetnacl": {
97 | "version": "1.0.3",
98 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
99 | "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
100 | },
101 | "ws": {
102 | "version": "7.2.5",
103 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz",
104 | "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA=="
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/C Version/print.c:
--------------------------------------------------------------------------------
1 | #include "print.h"
2 |
3 | #include
4 | #include
5 |
6 | #include "len str.h"
7 | #include "types.h"
8 |
9 | static const Calc_Len_Str_Size(1) list_start = {1, '['};
10 | static const Calc_Len_Str_Size(1) list_end = {1, ']'};
11 | static const Calc_Len_Str_Size(2) list_sep = {2, ',', ' '};
12 |
13 | static const Calc_Len_Str_Size(1) func_start = {1, '{'};
14 | static const Calc_Len_Str_Size(26) func_end = {26, ' ', '-', '>', ' ', '<', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', ' ', 'd', 'e', 'f', 'i', 'n', 'i', 't', 'i', 'o', 'n', '>', '}'};
15 | static const Calc_Len_Str_Size(1) func_sep = {1, ' '};
16 |
17 | static const Calc_Len_Str_Size(5) stack_start = {5, 'c', 'a', 'l', 'c', '='};
18 | static const Calc_Len_Str_Size(1) stack_sep = {1, ' '};
19 |
20 | Calc_Len_Str* calc_print(Calc_Stack* stack) {
21 | Calc_Val** vals = stack->vals;
22 | size_t len = stack->len;
23 | Calc_Len_Str** printed_vals;
24 | size_t buf_size;
25 | Calc_Len_Str* buf;
26 | size_t i;
27 |
28 | if(len == 0) return calc_to_len_str("calc=");
29 |
30 | printed_vals = malloc(sizeof(Calc_Len_Str*) * len);
31 |
32 | buf_size = stack_start.len + stack_sep.len * (len - 1);
33 | for(i = 0; i < len; i++) {
34 | printed_vals[i] = calc_print_val(vals[i]);
35 | buf_size += printed_vals[i]->len;
36 | }
37 |
38 | buf = calc_len_str_prealloc(buf_size);
39 | calc_len_str_append(buf, (const Calc_Len_Str*) &stack_start);
40 | for(i = 0; i < len; i++) {
41 | calc_len_str_append(buf, printed_vals[i]);
42 | if(i < len - 1)
43 | calc_len_str_append(buf, (const Calc_Len_Str*) &stack_sep);
44 | }
45 |
46 | for(i = 0; i < len; i++)
47 | free(printed_vals[i]);
48 | free(printed_vals);
49 |
50 | return buf;
51 | }
52 |
53 | Calc_Len_Str* calc_print_val(Calc_Val* val) {
54 | switch(val->type) {
55 | case calc_num: {
56 | int len = snprintf(NULL, 0, "%.5f", val->data.num);
57 | char* buf = malloc(sizeof(char) * len);
58 | Calc_Len_Str* len_str;
59 | sprintf(buf, "%.5f", val->data.num);
60 | len_str = calc_to_len_str(buf);
61 | free(buf);
62 | return len_str;
63 | }
64 | case calc_str: return calc_len_str_copy(val->data.str);
65 | case calc_list: {
66 | Calc_Val_List* val_data = val->data.list;
67 | size_t list_len = val_data->len;
68 | Calc_Len_Str** printed_vals;
69 | size_t buf_size;
70 | Calc_Len_Str* buf;
71 | size_t i;
72 |
73 | if(list_len == 0) return calc_to_len_str("[]");
74 |
75 | printed_vals = malloc(sizeof(Calc_Len_Str*) * list_len);
76 |
77 | buf_size =
78 | list_start.len +
79 | list_sep.len * (list_len - 1) +
80 | list_end.len;
81 | for(i = 0; i < list_len; i++) {
82 | printed_vals[i] = calc_print_val(val_data->vals[i]);
83 | buf_size += printed_vals[i]->len;
84 | }
85 |
86 | buf = calc_len_str_prealloc(buf_size);
87 | calc_len_str_append(buf, (const Calc_Len_Str*) &list_start);
88 | for(i = 0; i < list_len; i++) {
89 | calc_len_str_append(buf, printed_vals[i]);
90 | if(i < list_len - 1)
91 | calc_len_str_append(buf, (const Calc_Len_Str*) &list_sep);
92 | }
93 | calc_len_str_append(buf, (const Calc_Len_Str*) &list_end);
94 |
95 | for(i = 0; i < list_len; i++)
96 | free(printed_vals[i]);
97 | free(printed_vals);
98 |
99 | return buf;
100 | }
101 | case calc_func: {
102 | Calc_Len_Str** args = val->data.func->args.args;
103 | size_t args_len = val->data.func->args.len;
104 | size_t buf_size;
105 | Calc_Len_Str* buf;
106 | size_t i;
107 |
108 | if(args_len == 0) return calc_to_len_str("{}");
109 |
110 | buf_size =
111 | func_start.len +
112 | func_sep.len * (args_len - 1) +
113 | func_end.len;
114 | for(i = 0; i < args_len; i++)
115 | buf_size += args[i]->len;
116 |
117 | buf = calc_len_str_prealloc(buf_size);
118 | calc_len_str_append(buf, (const Calc_Len_Str*) &func_start);
119 | for(i = 0; i < args_len; i++) {
120 | calc_len_str_append(buf, args[i]);
121 | if(i < args_len - 1)
122 | calc_len_str_append(buf, (const Calc_Len_Str*) &func_sep);
123 | }
124 | calc_len_str_append(buf, (const Calc_Len_Str*) &func_end);
125 |
126 | return buf;
127 | }
128 | case calc_ref: return calc_len_str_copy(val->data.ref->sym);
129 | case calc_op: return calc_len_str_copy(calc_op_to_str(val->data.op));
130 | }
131 | }
132 |
133 | void calc_debug_stack(Calc_Stack* stack) {
134 | Calc_Len_Str* str = calc_print(stack);
135 | char* c_str = calc_from_len_str(str);
136 | printf("%s\n", c_str);
137 | free(str);
138 | free(c_str);
139 | }
140 |
141 | void calc_debug_val(Calc_Val* val) {
142 | Calc_Len_Str* str = calc_print_val(val);
143 | char* c_str = calc_from_len_str(str);
144 | printf("%s", c_str);
145 | free(str);
146 | free(c_str);
147 | }
148 |
--------------------------------------------------------------------------------
/calc/run part.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var types = require("./types");
4 | var variable_manipulation = require("./variable manipulation");
5 |
6 | function run_function(func, stack, built_ins, operators, end_time) {
7 | if(Date.now() > end_time) {
8 | throw "Error: code took too long to run, stopped.";
9 | }
10 | if(!func.is_ref || [types.func, types.op].includes(func.type)) {
11 | switch(func.type) {
12 | case types.func:
13 | var args = {};
14 | var variables = {};
15 | var scopes = func.scopes.concat(args, variables);
16 |
17 | for(let cou = 0; cou < func.args.length; cou++) {
18 | args[func.args[func.args.length - cou - 1]] = stack.pop();
19 | }
20 |
21 | for(let cou = 0; cou < func.variables.length; cou++) {
22 | run_block(func.variables[cou].data, stack, scopes, built_ins, operators, end_time);
23 | var value = stack.pop();
24 | if(value == undefined) {
25 | throw `Expected stack to have at least 1 item when defining the variable "${func.variables[cou].name}".`;
26 | }
27 | variables[func.variables[cou].name] = value;
28 | }
29 |
30 | run_block(func.data, stack, scopes, built_ins, operators, end_time);
31 | break;
32 | case types.sym:
33 | built_ins[func.data](scopes);
34 | break;
35 | case types.op:
36 | operators[func.data]();
37 | break;
38 | }
39 | } else {
40 | stack.push({data: JSON.parse(JSON.stringify(func.data)), type: func.type});
41 | }
42 | }
43 |
44 | function run_block(block, stack, scopes, built_ins, operators, end_time) {
45 | if(Date.now() > end_time) {
46 | throw "Error: code took too long to run, stopped.";
47 | }
48 | for(let instruccion_pointer = 0; instruccion_pointer < block.length; instruccion_pointer++) {
49 | if(Date.now() > end_time) {
50 | throw "Error: code took too long to run, stopped.";
51 | }
52 |
53 | switch(block[instruccion_pointer].type) {
54 | case types.sym:
55 | if(variable_manipulation.get_variable(block[instruccion_pointer].data, scopes)) {
56 | switch(variable_manipulation.get_variable(block[instruccion_pointer].data, scopes).type) {
57 | case types.func:
58 | run_function(variable_manipulation.get_variable(block[instruccion_pointer].data, scopes), stack, built_ins, operators, end_time);
59 | break;
60 | case types.sym:
61 | built_ins[variable_manipulation.get_variable(block[instruccion_pointer].data, scopes).data](scopes);
62 | break;
63 | case types.op:
64 | operators[variable_manipulation.get_variable(block[instruccion_pointer].data, scopes).data]();
65 | break;
66 | default:
67 | stack.push(JSON.parse(JSON.stringify(variable_manipulation.get_variable(block[instruccion_pointer].data, scopes))));
68 | break;
69 | }
70 | } else if(built_ins[block[instruccion_pointer].data]) {
71 | built_ins[block[instruccion_pointer].data](scopes);
72 | } else {
73 | throw `Error: symbol "${block[instruccion_pointer].data}" found in main expression without being a built-in function.`;
74 | }
75 | break;
76 | case types.num:
77 | case types.str:
78 | stack.push(block[instruccion_pointer]);
79 | break;
80 | case types.list:
81 | var list = [];
82 | for(let cou = 0; cou < block[instruccion_pointer].data; cou++) {
83 | list.push(stack.pop());
84 | }
85 | stack.push(types.new_list(list.reverse()));
86 | break;
87 | case types.func:
88 | var scoped_function = block[instruccion_pointer];
89 | scoped_function.scopes = scopes;
90 | stack.push(scoped_function);
91 | break;
92 | case types.op:
93 | if(block[instruccion_pointer].data != "$") {
94 | operators[block[instruccion_pointer].data]();
95 | } else {
96 | instruccion_pointer++;
97 | if(instruccion_pointer < block.length) {
98 | switch(block[instruccion_pointer].type) {
99 | case types.sym:
100 | if(variable_manipulation.get_variable(block[instruccion_pointer].data, scopes)) {
101 | var passed_function = variable_manipulation.get_variable(block[instruccion_pointer].data, scopes);
102 | passed_function.name = block[instruccion_pointer].data;
103 | passed_function.is_ref = true;
104 | stack.push(passed_function);
105 | } else {
106 | stack.push(block[instruccion_pointer]);
107 | }
108 | break;
109 | case types.op:
110 | stack.push(block[instruccion_pointer]);
111 | break;
112 | default:
113 | var reference = block[instruccion_pointer];
114 | reference.is_ref = true;
115 | stack.push(reference);
116 | break;
117 | }
118 | } else {
119 | throw `Error: there is a "$" at the end of the code without anything to follow.`;
120 | }
121 | }
122 | break;
123 | }
124 | }
125 | }
126 |
127 | module.exports = {run_function, run_block};
--------------------------------------------------------------------------------
/calc/parse.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var types = require("./types");
4 |
5 | function parse(tokens) {
6 | var token_pointer = 0;
7 |
8 | function parse_function() {
9 | token_pointer++;
10 | var args = [];
11 |
12 | var has_arrow = false;
13 | var end = token_pointer;
14 | var function_depth = 0;
15 | while(!is_op(tokens[end], "}") && end < tokens.length) {
16 | if(is_op(tokens[end], "->") && !function_depth) {
17 | has_arrow = true;
18 | } else if(is_op(tokens[end], "{")) {
19 | function_depth++;
20 | } else if(is_op(tokens[end], "}")) {
21 | function_depth--;
22 | }
23 | end++;
24 | }
25 |
26 | if(has_arrow) {
27 | while(!is_op(tokens[token_pointer], "->") && token_pointer < tokens.length) {
28 | if(tokens[token_pointer].type == types.sym) {
29 | args.push(tokens[token_pointer].data);
30 | } else {
31 | throw `Error: parameter name "${tokens[token_pointer].data}" is a ${types.type_to_str(tokens[token_pointer].type)} when it should be a symbol.`;
32 | }
33 | token_pointer++;
34 | }
35 | token_pointer++;
36 | }
37 |
38 | var raw_variables = [];
39 | var variable = [];
40 | while(!is_op(tokens[token_pointer], "}") && token_pointer < tokens.length) {
41 | if([types.sym, types.num, types.str].includes(tokens[token_pointer].type)) {
42 | variable.push(tokens[token_pointer]);
43 | token_pointer++;
44 | } else if(!is_op(tokens[token_pointer], "{") && !is_op(tokens[token_pointer], "[")) {
45 | if(is_op(tokens[token_pointer], ";")) {
46 | raw_variables.push(variable);
47 | variable = [];
48 | } else {
49 | variable.push(tokens[token_pointer]);
50 | }
51 | token_pointer++;
52 | } else {
53 | if(is_op(tokens[token_pointer], "{")) {
54 | variable.push(parse_function());
55 | } else {
56 | variable.push(...parse_list());
57 | }
58 | }
59 | }
60 | var code = variable;
61 | var variables = raw_variables.map(raw_variable => {
62 | if(raw_variable.length < 2) {
63 | throw "Error: variable definition too short.";
64 | }
65 | if(!is_op(raw_variable[1], "=")) {
66 | throw "Error: variable definition has no \"=\".";
67 | }
68 | if(raw_variable[0].type != types.sym) {
69 | throw `Error: variable name is a ${types.type_to_str(raw_variable[0].type)} when it should be a symbol.`;
70 | }
71 | return {name: raw_variable[0].data, data: raw_variable.slice(2)};
72 | });
73 | token_pointer++;
74 |
75 | return {args, variables, data: code, type: types.func};
76 | }
77 |
78 | function parse_list() {
79 | token_pointer++;
80 |
81 | var code = [];
82 | var length = 0;
83 | while(!is_op(tokens[token_pointer], "]") && token_pointer < tokens.length) {
84 | if(is_op(tokens[token_pointer], ",")) {
85 | length++;
86 | token_pointer++;
87 | } else if([types.sym, types.num, types.str].includes(tokens[token_pointer].type)) {
88 | code.push(tokens[token_pointer]);
89 | token_pointer++;
90 | } else if(!is_op(tokens[token_pointer], "{") && !is_op(tokens[token_pointer], "[")) {
91 | if(!/,|\]|}|->/.test(tokens[token_pointer].data)) {
92 | code.push(tokens[token_pointer]);
93 | } else {
94 | throw `Error: unexpected context operator "${tokens[token_pointer].data}".`;
95 | }
96 | token_pointer++;
97 | } else {
98 | if(is_op(tokens[token_pointer], "{")) {
99 | code.push(parse_function());
100 | } else {
101 | code.push(...parse_list());
102 | }
103 | }
104 | }
105 | if(code.length || length > 0) {
106 | length++;
107 | }
108 | token_pointer++;
109 |
110 | return [...code, types.new_list(length)];
111 | }
112 |
113 | var raw_variables = [];
114 | var variable = [];
115 | while(token_pointer < tokens.length) {
116 | if([types.sym, types.num, types.str].includes(tokens[token_pointer].type)) {
117 | variable.push(tokens[token_pointer]);
118 | token_pointer++;
119 | } else if(!is_op(tokens[token_pointer], "{") && !is_op(tokens[token_pointer], "[")) {
120 | if(!/,|\]|}|->/.test(tokens[token_pointer].data)) {
121 | if(is_op(tokens[token_pointer], ";")) {
122 | raw_variables.push(variable);
123 | variable = [];
124 | } else {
125 | variable.push(tokens[token_pointer]);
126 | }
127 | } else {
128 | throw `Error: unexpected context operator "${tokens[token_pointer].data}".`;
129 | }
130 | token_pointer++;
131 | } else {
132 | if(tokens[token_pointer].data == "{") {
133 | variable.push(parse_function());
134 | } else {
135 | variable.push(...parse_list());
136 | }
137 | }
138 | }
139 | var ast = variable;
140 | var variables = raw_variables.map(raw_variable => {
141 | if(raw_variable.length < 2) {
142 | throw "Error: variable definition too short.";
143 | }
144 | if(!is_op(raw_variable[1], "=")) {
145 | throw "Error: variable definition has no \"=\".";
146 | }
147 | if(raw_variable[0].type != types.sym) {
148 | throw `Error: variable name is a ${types.type_to_str(raw_variable[0].type)} when it should be a symbol.`;
149 | }
150 | return {name: raw_variable[0].data, data: raw_variable.slice(2)};
151 | });
152 |
153 | return {variables, data: ast};
154 | }
155 |
156 | var is_op = (token, op) => token.data == op && token.type == types.op;
157 |
158 | module.exports = parse;
--------------------------------------------------------------------------------
/C Version/builtins.h:
--------------------------------------------------------------------------------
1 | /* ANSI-C code produced by gperf version 3.1 */
2 | /* Command-line: 'C:\\ProgramData\\chocolatey\\lib\\gperf\\tools\\gperf.exe' -c -t '.\\builtins.gperf' */
3 | /* Computed positions: -k'1' */
4 |
5 | #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
6 | && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
7 | && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
8 | && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
9 | && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
10 | && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
11 | && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
12 | && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
13 | && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
14 | && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
15 | && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
16 | && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
17 | && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
18 | && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
19 | && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
20 | && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
21 | && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
22 | && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
23 | && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
24 | && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
25 | && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
26 | && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
27 | && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
28 | /* The character set is not based on ISO-646. */
29 | #error "gperf generated tables don't work with this execution character set. Please report a bug to ."
30 | #endif
31 |
32 | #line 1 ".\\builtins.gperf"
33 |
34 | #ifndef CALC_BUILTINS
35 | #define CALC_BUILTINS
36 |
37 | #include
38 | #include
39 |
40 | #include "types.h"
41 |
42 | #define __builtin(name) void name( \
43 | Calc_Stack* stack, \
44 | Calc_Scopes* scopes, \
45 | void* custom_builtins, \
46 | time_t end_time \
47 | )
48 |
49 | __builtin(calc_builtin_type) {
50 | Calc_Val* val = calc_pop(stack);
51 | calc_push(stack, calc_new_str(calc_len_str_copy(calc_type_to_str(val->type))));
52 | calc_lose_ref(val);
53 | }
54 |
55 | __builtin(calc_builtin_dup) {
56 | Calc_Val* val = calc_peek(stack);
57 | calc_gain_ref(val);
58 | calc_push(stack, val);
59 | }
60 |
61 | __builtin(calc_builtin_drop) {
62 | calc_lose_ref(calc_pop(stack));
63 | }
64 | #line 35 ".\\builtins.gperf"
65 | struct Calc_Lookup_Builtin {char* name; Calc_Builtin builtin;};
66 |
67 | #define TOTAL_KEYWORDS 3
68 | #define MIN_WORD_LENGTH 3
69 | #define MAX_WORD_LENGTH 4
70 | #define MIN_HASH_VALUE 3
71 | #define MAX_HASH_VALUE 5
72 | /* maximum key range = 3, duplicates = 0 */
73 |
74 | #ifdef __GNUC__
75 | __inline
76 | #else
77 | #ifdef __cplusplus
78 | inline
79 | #endif
80 | #endif
81 | static unsigned int
82 | hash_builtins (register const char *str, register size_t len)
83 | {
84 | static unsigned char asso_values[] =
85 | {
86 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
87 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
88 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
89 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
90 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
91 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
92 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
93 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
94 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
95 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
96 | 0, 6, 6, 6, 6, 6, 6, 6, 6, 6,
97 | 6, 6, 6, 6, 6, 6, 1, 6, 6, 6,
98 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
99 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
100 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
101 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
102 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
103 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
104 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
105 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
106 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
107 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
108 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
109 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
110 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
111 | 6, 6, 6, 6, 6, 6
112 | };
113 | return len + asso_values[(unsigned char)str[0]];
114 | }
115 |
116 | struct Calc_Lookup_Builtin *
117 | get_builtin (register const char *str, register size_t len)
118 | {
119 | static struct Calc_Lookup_Builtin wordlist[] =
120 | {
121 | {""}, {""}, {""},
122 | #line 38 ".\\builtins.gperf"
123 | {"dup", calc_builtin_dup},
124 | #line 39 ".\\builtins.gperf"
125 | {"drop", calc_builtin_drop},
126 | #line 37 ".\\builtins.gperf"
127 | {"type", calc_builtin_type}
128 | };
129 |
130 | if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
131 | {
132 | register unsigned int key = hash_builtins (str, len);
133 |
134 | if (key <= MAX_HASH_VALUE)
135 | {
136 | register const char *s = wordlist[key].name;
137 |
138 | if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
139 | return &wordlist[key];
140 | }
141 | }
142 | return 0;
143 | }
144 | #line 40 ".\\builtins.gperf"
145 |
146 | #undef TOTAL_KEYWORDS
147 | #undef MIN_WORD_LENGTH
148 | #undef MAX_WORD_LENGTH
149 | #undef MIN_HASH_VALUE
150 | #undef MAX_HASH_VALUE
151 |
152 | #endif
153 |
--------------------------------------------------------------------------------
/C Version/aliases.h:
--------------------------------------------------------------------------------
1 | /* ANSI-C code produced by gperf version 3.1 */
2 | /* Command-line: 'C:\\ProgramData\\chocolatey\\lib\\gperf\\tools\\gperf.exe' -c -t '.\\aliases.gperf' */
3 | /* Computed positions: -k'1' */
4 |
5 | #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
6 | && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
7 | && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
8 | && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
9 | && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
10 | && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
11 | && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
12 | && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
13 | && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
14 | && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
15 | && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
16 | && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
17 | && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
18 | && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
19 | && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
20 | && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
21 | && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
22 | && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
23 | && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
24 | && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
25 | && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
26 | && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
27 | && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
28 | /* The character set is not based on ISO-646. */
29 | #error "gperf generated tables don't work with this execution character set. Please report a bug to ."
30 | #endif
31 |
32 | #line 1 ".\\aliases.gperf"
33 |
34 | #ifndef CALC_ALIASES
35 | #define CALC_ALIASES
36 |
37 | #include
38 | #include
39 |
40 | #include "len str.h"
41 |
42 | static const Calc_Len_Str calc_type_main_alias = {4, 't', 'y', 'p', 'e'};
43 | static const Calc_Len_Str calc_dup_main_alias = {3, 'd', 'u', 'p'};
44 | static const Calc_Len_Str calc_drop_main_alias = {4, 'd', 'r', 'o', 'p'};
45 | #line 16 ".\\aliases.gperf"
46 | struct Calc_Alias {char* name; const Calc_Len_Str* main_alias;};
47 |
48 | #define TOTAL_KEYWORDS 8
49 | #define MIN_WORD_LENGTH 3
50 | #define MAX_WORD_LENGTH 10
51 | #define MIN_HASH_VALUE 4
52 | #define MAX_HASH_VALUE 19
53 | /* maximum key range = 16, duplicates = 0 */
54 |
55 | #ifdef __GNUC__
56 | __inline
57 | #else
58 | #ifdef __cplusplus
59 | inline
60 | #endif
61 | #endif
62 | static unsigned int
63 | hash_aliases (register const char *str, register size_t len)
64 | {
65 | static unsigned char asso_values[] =
66 | {
67 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
68 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
69 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
70 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
71 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
72 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
73 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
74 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
75 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
76 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
77 | 5, 20, 20, 20, 20, 5, 20, 20, 20, 20,
78 | 20, 20, 20, 20, 20, 10, 0, 20, 20, 20,
79 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
80 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
81 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
82 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
83 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
84 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
85 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
86 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
87 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
88 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
89 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
90 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
91 | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
92 | 20, 20, 20, 20, 20, 20
93 | };
94 | return len + asso_values[(unsigned char)str[0]];
95 | }
96 |
97 | struct Calc_Alias *
98 | get_main_alias (register const char *str, register size_t len)
99 | {
100 | static struct Calc_Alias wordlist[] =
101 | {
102 | {""}, {""}, {""}, {""},
103 | #line 18 ".\\aliases.gperf"
104 | {"type", &calc_type_main_alias},
105 | {""},
106 | #line 19 ".\\aliases.gperf"
107 | {"typeof", &calc_type_main_alias},
108 | {""},
109 | #line 23 ".\\aliases.gperf"
110 | {"dup", &calc_dup_main_alias},
111 | #line 26 ".\\aliases.gperf"
112 | {"drop", &calc_drop_main_alias},
113 | {""}, {""}, {""},
114 | #line 20 ".\\aliases.gperf"
115 | {"instance", &calc_type_main_alias},
116 | #line 24 ".\\aliases.gperf"
117 | {"duplicate", &calc_dup_main_alias},
118 | #line 21 ".\\aliases.gperf"
119 | {"instanceof", &calc_type_main_alias},
120 | {""}, {""}, {""},
121 | #line 27 ".\\aliases.gperf"
122 | {"stack_pop", &calc_drop_main_alias}
123 | };
124 |
125 | if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
126 | {
127 | register unsigned int key = hash_aliases (str, len);
128 |
129 | if (key <= MAX_HASH_VALUE)
130 | {
131 | register const char *s = wordlist[key].name;
132 |
133 | if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
134 | return &wordlist[key];
135 | }
136 | }
137 | return 0;
138 | }
139 | #line 28 ".\\aliases.gperf"
140 |
141 | #undef TOTAL_KEYWORDS
142 | #undef MIN_WORD_LENGTH
143 | #undef MAX_WORD_LENGTH
144 | #undef MIN_HASH_VALUE
145 | #undef MAX_HASH_VALUE
146 |
147 | #endif
148 |
--------------------------------------------------------------------------------
/C Version/types.c:
--------------------------------------------------------------------------------
1 | #include "types.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include /* Hide this behind a debug macro later. */
10 |
11 | #include "len str.h"
12 |
13 | Calc_Val* calc_new_num(double num) {
14 | Calc_Val* val = malloc(sizeof(Calc_Val));
15 | val->type = calc_num;
16 | val->data.num = num;
17 | val->refs = 1;
18 | return val;
19 | }
20 |
21 | Calc_Val* calc_new_bool(bool bool_) {
22 | Calc_Val* val = malloc(sizeof(Calc_Val));
23 | val->type = calc_num;
24 | val->data.num = bool_ ? 1.0 : 0.0;
25 | val->refs = 1;
26 | return val;
27 | }
28 |
29 | Calc_Val* calc_new_str(Calc_Len_Str* str) {
30 | Calc_Val* val = malloc(sizeof(Calc_Val));
31 | val->type = calc_str;
32 | val->data.str = str;
33 | val->refs = 1;
34 | return val;
35 | }
36 |
37 | Calc_Val* calc_new_ref(Calc_Len_Str* sym, Calc_Scopes scopes) {
38 | Calc_Val* val = malloc(sizeof(Calc_Val));
39 | val->type = calc_ref;
40 | val->data.ref = malloc(sizeof(Calc_Ref));
41 | *(val->data.ref) = (Calc_Ref) {
42 | .sym = sym,
43 | .scopes = scopes
44 | };
45 | val->refs = 1;
46 | return val;
47 | }
48 |
49 | Calc_Val* calc_new_op(Calc_Op op) {
50 | Calc_Val* val = malloc(sizeof(Calc_Val));
51 | val->type = calc_op;
52 | val->data.op = op;
53 | val->refs = 1;
54 | return val;
55 | }
56 |
57 | bool calc_is_num(Calc_Val* val) {
58 | return val->type == calc_num;
59 | }
60 |
61 | bool calc_is_str(Calc_Val* val) {
62 | return val->type == calc_str;
63 | }
64 |
65 | bool calc_is_list(Calc_Val* val) {
66 | return val->type == calc_list;
67 | }
68 |
69 | bool calc_is_func(Calc_Val* val) {
70 | return val->type == calc_func;
71 | }
72 |
73 | bool calc_is_ref(Calc_Val* val) {
74 | return val->type == calc_ref;
75 | }
76 |
77 | bool calc_is_op(Calc_Val* val) {
78 | return val->type == calc_op;
79 | }
80 |
81 | bool calc_is_list_like(Calc_Val* val) {
82 | return calc_is_str(val) || calc_is_list(val);
83 | }
84 |
85 | static const Calc_Len_Str_Size(6) calc_num_str = {6, 'n', 'u', 'm', 'b', 'e', 'r'};
86 | static const Calc_Len_Str_Size(6) calc_str_str = {6, 's', 't', 'r', 'i', 'n', 'g'};
87 | static const Calc_Len_Str_Size(4) calc_list_str = {4, 'l', 'i', 's', 't'};
88 | static const Calc_Len_Str_Size(8) calc_func_str = {8, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n'};
89 | static const Calc_Len_Str_Size(9) calc_ref_str = {9, 'r', 'e', 'f', 'e', 'r', 'e', 'n', 'c', 'e'};
90 | static const Calc_Len_Str_Size(8) calc_op_str = {8, 'o', 'p', 'e', 'r', 'a', 't', 'o', 'r'};
91 |
92 | const Calc_Len_Str* calc_type_to_str(Calc_Type type) {
93 | switch(type) {
94 | case calc_num: return (const Calc_Len_Str*) &calc_num_str;
95 | case calc_str: return (const Calc_Len_Str*) &calc_str_str;
96 | case calc_list: return (const Calc_Len_Str*) &calc_list_str;
97 | case calc_func: return (const Calc_Len_Str*) &calc_func_str;
98 | case calc_ref: return (const Calc_Len_Str*) &calc_ref_str;
99 | case calc_op: return (const Calc_Len_Str*) &calc_op_str;
100 | }
101 | }
102 |
103 | bool calc_val_to_bool(Calc_Val* val) {
104 | switch(val->type) {
105 | case calc_num: return !calc_dbl_eq(val->data.num, 0.0);
106 | case calc_str: return val->data.str->len != 0;
107 | case calc_list: return val->data.list->len != 0;
108 | case calc_func:
109 | case calc_ref:
110 | case calc_op:
111 | return true;
112 | }
113 | }
114 |
115 | bool calc_dbl_eq(double n, double m) {
116 | return fabs(n - m) < 0.000005 - DBL_EPSILON;
117 | }
118 |
119 | bool calc_eq(Calc_Val* v, Calc_Val* u) {
120 | if(calc_is_num(v) && calc_is_num(u)) {
121 | return calc_dbl_eq(v->data.num, u->data.num);
122 | } else if(calc_is_str(v) && calc_is_str(u)) {
123 | Calc_Len_Str* v_data = v->data.str;
124 | Calc_Len_Str* u_data = u->data.str;
125 | if(v_data->len == u_data->len) {
126 | return memcmp(v_data->chars, u_data->chars, v_data->len) == 0;
127 | } else return false;
128 | } else if(calc_is_list(v) && calc_is_list(u)) {
129 | Calc_Val_List* v_data = v->data.list;
130 | Calc_Val_List* u_data = u->data.list;
131 | if(v_data->len == u_data->len) {
132 | size_t i;
133 | for(i = 0; i < v_data->len; i++) {
134 | if(!calc_eq(v_data->vals[i], u_data->vals[i]))
135 | return false;
136 | }
137 | return true;
138 | } else return false;
139 | } else return false;
140 | }
141 |
142 | bool calc_cmp(Calc_Val* v, Calc_Val* u, bool comp(double, double)) {
143 | if(
144 | calc_is_func(v) || calc_is_ref(v) || calc_is_op(v) ||
145 | calc_is_func(u) || calc_is_ref(u) || calc_is_op(u))
146 | return false;
147 |
148 | double v_num;
149 | double u_num;
150 |
151 | if(calc_is_num(v))
152 | v_num = v->data.num;
153 | else if(calc_is_str(v))
154 | v_num = (double) v->data.str->len;
155 | else /* Must be a list. */
156 | v_num = (double) v->data.list->len;
157 |
158 | if(calc_is_num(u))
159 | u_num = u->data.num;
160 | else if(calc_is_str(u))
161 | u_num = (double) u->data.str->len;
162 | else /* Must be a list. */
163 | u_num = (double) u->data.list->len;
164 |
165 | return comp(v_num, u_num);
166 | }
167 |
168 | #include "print.h"
169 | void calc_free_val(Calc_Val* val) {
170 | printf("Freeing ");
171 | calc_debug_val(val);
172 | printf("\n");
173 | switch(val->type) {
174 | case calc_num: break;
175 | case calc_str: free(val->data.str); break;
176 | case calc_list: {
177 | Calc_Val_List* list = val->data.list;
178 | size_t i;
179 | for(i = 0; i < list->len; i++)
180 | calc_lose_ref(list->vals[i]);
181 | free(list);
182 | break;
183 | }
184 | }
185 | free(val);
186 | }
187 |
188 | void calc_gain_ref(Calc_Val* val) {
189 | val->refs++;
190 | }
191 |
192 | void calc_lose_ref(Calc_Val* val) {
193 | if(--val->refs == 0)
194 | calc_free_val(val);
195 | else {calc_debug_val(val); printf(" is down to %d ref(s).\n", val->refs);}
196 | }
197 |
198 | Calc_Stack calc_new_stack(size_t start_cap) {
199 | return (Calc_Stack) {
200 | .len = 0,
201 | .cap = start_cap,
202 | .vals = malloc(sizeof(Calc_Val*) * start_cap)
203 | };
204 | }
205 |
206 | void calc_free_stack(Calc_Stack* stack) {
207 | size_t i;
208 | for(i = 0; i < stack->len; i++)
209 | calc_lose_ref(stack->vals[i]);
210 | free(stack->vals);
211 | stack->vals = NULL;
212 | stack->cap = stack->len = 0;
213 | }
214 |
215 | void calc_push(Calc_Stack* stack, Calc_Val* val) {
216 | if(++stack->len > stack->cap) {
217 | stack->cap *= 2;
218 | stack->vals = realloc(stack->vals, sizeof(Calc_Val*) * stack->cap);
219 | }
220 | stack->vals[stack->len-1] = val;
221 | }
222 |
223 | Calc_Val* calc_pop(Calc_Stack* stack) {
224 | return stack->vals[--stack->len];
225 | }
226 |
227 | Calc_Val* calc_peek(Calc_Stack* stack) {
228 | return stack->vals[stack->len-1];
229 | }
230 |
--------------------------------------------------------------------------------
/C Version/lex.c:
--------------------------------------------------------------------------------
1 | #include "lex.h"
2 |
3 | #include
4 |
5 | #include /* Hide this behind a debug macro later. */
6 |
7 | #include "len str.h"
8 |
9 | #define is_digit(curr) ((curr) >= '0' && (curr) <= '9')
10 |
11 | /* A num op is the first character of an operator which can also be the first character of a number. */
12 |
13 | #define is_non_num_op_char(curr) ( \
14 | (curr) == '+' || (curr) == '*' || (curr) == '/' || \
15 | (curr) == '^' || (curr) == '%' || \
16 | (curr) == '&' || (curr) == '|' || (curr) == '!' || \
17 | (curr) == '=' || (curr) == '<' || (curr) == '>' || \
18 | (curr) == '\'' || \
19 | (curr) == '[' || (curr) == ']' || (curr) == ',' || \
20 | (curr) == '{' || (curr) == '}' || \
21 | (curr) == ':' || (curr) == ';' \
22 | )
23 |
24 | #define is_num_op_char(curr) ((curr) == '-' || (curr) == '.')
25 |
26 | #define is_whitespace(curr) ( \
27 | (curr) == ' ' || (curr) == '\t' || (curr) == '\n' || (curr) == '\r' \
28 | )
29 |
30 | Calc_Tokens calc_lex(const Calc_Len_Str* prog) {
31 | Calc_Tokens tokens;
32 | size_t pos = 0;
33 | char curr;
34 | int succeeded;
35 |
36 | tokens.len = 0;
37 | tokens.cap = 128;
38 | tokens.tokens = malloc(sizeof(Calc_Token) * 128);
39 |
40 | while(pos < prog->len) {
41 | curr = prog->chars[pos];
42 | if(is_digit(curr)) calc_expect_num(&tokens, prog, &pos);
43 | else if(is_num_op_char(curr)) {
44 | if(
45 | (pos + 1 < prog->len && is_digit(prog->chars[pos + 1])) ||
46 | (
47 | pos + 2 < prog->len &&
48 | prog->chars[pos + 1] == '.' &&
49 | is_digit(prog->chars[pos + 2]))
50 | ) calc_expect_num(&tokens, prog, &pos);
51 | else {
52 | succeeded = calc_expect_op(&tokens, prog, &pos);
53 | if(!succeeded) return tokens;
54 | }
55 | } else if(curr == '"') {
56 | succeeded = calc_expect_str(&tokens, prog, &pos);
57 | if(!succeeded) return tokens;
58 | }
59 | else if(is_non_num_op_char(curr)) {
60 | succeeded = calc_expect_op(&tokens, prog, &pos);
61 | if(!succeeded) return tokens;
62 | }
63 | else if(!is_whitespace(curr)) calc_expect_sym(&tokens, prog, &pos);
64 | else pos++;
65 | }
66 |
67 | return tokens;
68 | }
69 |
70 | void calc_expect_num(
71 | Calc_Tokens* tokens,
72 | const Calc_Len_Str* prog,
73 | size_t* pos
74 | ) {
75 | size_t end = *pos;
76 | char* num_str;
77 | double num;
78 | Calc_Token token;
79 |
80 | if(prog->chars[end] == '-') end++;
81 | while(end < prog->len && is_digit(prog->chars[end])) end++;
82 | if(
83 | end + 1 < prog->len &&
84 | prog->chars[end] == '.' &&
85 | is_digit(prog->chars[end + 1])
86 | ) {
87 | end++;
88 | while(end < prog->len && is_digit(prog->chars[end])) end++;
89 | }
90 |
91 | num_str = calc_from_len_str_slice(prog, *pos, end - *pos);
92 | num = strtod(num_str, NULL);
93 | free(num_str);
94 |
95 | printf("Num: %f\n", num);
96 |
97 | token.type = calc_num_token;
98 | token.data.num = num;
99 | calc_append_token(tokens, token);
100 |
101 | *pos = end;
102 | }
103 |
104 | int calc_expect_str(
105 | Calc_Tokens* tokens,
106 | const Calc_Len_Str* prog,
107 | size_t* pos
108 | ) {
109 | size_t end = *pos + 1;
110 | size_t escapes = 0;
111 | Calc_Len_Str* str;
112 | size_t i;
113 | char* buf;
114 | Calc_Token token;
115 |
116 | while(end < prog->len && prog->chars[end] != '"') {
117 | if(prog->chars[end] == '\\') {
118 | if(end + 1 < prog->len) {
119 | end++;
120 | escapes++;
121 | } else return 0;
122 | }
123 | end++;
124 | }
125 | if(prog->chars[end] != '"') return 0;
126 | end++;
127 |
128 | str = calc_len_str_prealloc(end - *pos - escapes - 2);
129 | for(i = *pos + 1; i < end - 1; i++) {
130 | if(prog->chars[i] == '\\') {
131 | i++;
132 | switch(prog->chars[i]) {
133 | case 'n': {str->chars[str->len] = '\n'; break;}
134 | case 't': {str->chars[str->len] = '\t'; break;}
135 | default: {str->chars[str->len] = prog->chars[i]; break;}
136 | }
137 | str->len++;
138 | } else {
139 | str->chars[str->len] = prog->chars[i];
140 | str->len++;
141 | }
142 | }
143 |
144 | buf = calc_from_len_str(str);
145 | printf("Str: \"%s\"\n", buf);
146 | free(buf);
147 |
148 | token.type = calc_str_token;
149 | token.data.str = str;
150 | calc_append_token(tokens, token);
151 |
152 | *pos = end;
153 | return 1;
154 | }
155 |
156 | int calc_expect_op(
157 | Calc_Tokens* tokens,
158 | const Calc_Len_Str* prog,
159 | size_t* pos
160 | ) {
161 | Calc_Op op;
162 | char curr = prog->chars[*pos];
163 | char next = *pos + 1 < prog->len ? prog->chars[*pos + 1] : '\0';
164 | char* buf;
165 | Calc_Token token;
166 |
167 | if(curr == '+') op = calc_add;
168 | else if(curr == '-') {
169 | if(next == '>') {op = calc_func_arrow; (*pos)++;}
170 | else op = calc_sub;
171 | } else if(curr == '*') op = calc_mul;
172 | else if(curr == '/') op = calc_div;
173 | else if(curr == '^') op = calc_pow;
174 | else if(curr == '%') op = calc_mod;
175 | else if(curr == '.') {
176 | if(next == '.') {op = calc_to; (*pos)++;}
177 | else return 0;
178 | } else if(curr == '&') op = calc_and;
179 | else if(curr == '|') op = calc_or;
180 | else if(curr == '!') {
181 | if(next == '=') {op = calc_neq; (*pos)++;}
182 | else op = calc_not;
183 | } else if(curr == '=') op = calc_eq_;
184 | else if(curr == '<') {
185 | if(next == '=') {op = calc_lte; (*pos)++;}
186 | else op = calc_lt;
187 | } else if(curr == '>') {
188 | if(next == '=') {op = calc_gte; (*pos)++;}
189 | else op = calc_gt;
190 | } else if(curr == '\'') op = calc_refof;
191 | else if(curr == '[') op = calc_list_start;
192 | else if(curr == ']') op = calc_list_end;
193 | else if(curr == ',') op = calc_list_sep;
194 | else if(curr == '{') op = calc_func_start;
195 | else if(curr == '}') op = calc_func_end;
196 | else if(curr == ':') {
197 | if(next == '=') {op = calc_var_decl; (*pos)++;}
198 | else return 0;
199 | } else if(curr == ';') op = calc_list_start;
200 |
201 | buf = calc_from_len_str(calc_op_to_str(op));
202 | printf("Op: %s\n", buf);
203 | free(buf);
204 |
205 | token.type = calc_op_token;
206 | token.data.op = op;
207 | calc_append_token(tokens, token);
208 |
209 | (*pos)++;
210 | return 1;
211 | }
212 |
213 | void calc_expect_sym(
214 | Calc_Tokens* tokens,
215 | const Calc_Len_Str* prog,
216 | size_t* pos
217 | ) {
218 | size_t end = *pos;
219 | Calc_Len_Str* sym;
220 | size_t i;
221 | char* buf;
222 | Calc_Token token;
223 |
224 | while(
225 | end < prog->len &&
226 | !is_digit(prog->chars[end]) &&
227 | !is_non_num_op_char(prog->chars[end]) &&
228 | !is_num_op_char(prog->chars[end]) &&
229 | !is_whitespace(prog->chars[end]) &&
230 | prog->chars[end] != '"'
231 | ) end++;
232 |
233 | sym = calc_len_str_prealloc(end - *pos);
234 | for(i = *pos; i < end; i++) {
235 | sym->chars[sym->len] = prog->chars[i];
236 | sym->len++;
237 | }
238 |
239 | buf = calc_from_len_str(sym);
240 | printf("Sym: %s\n", buf);
241 | free(buf);
242 |
243 | token.type = calc_sym_token;
244 | token.data.sym = sym;
245 | calc_append_token(tokens, token);
246 |
247 | *pos = end;
248 | }
249 |
250 | void calc_free_tokens(Calc_Tokens tokens) {
251 | size_t i;
252 | for(i = 0; i < tokens.len; i++) {
253 | switch(tokens.tokens[i].type) {
254 | case calc_num_token:
255 | case calc_op_token:
256 | break;
257 | case calc_str_token: {free(tokens.tokens[i].data.str); break;}
258 | case calc_sym_token: {free(tokens.tokens[i].data.sym); break;}
259 | }
260 | }
261 | free(tokens.tokens);
262 | }
263 |
264 | void calc_append_token(Calc_Tokens* tokens, Calc_Token token) {
265 | if(++tokens->len > tokens->cap) {
266 | tokens->cap *= 2;
267 | tokens->tokens = realloc(tokens->tokens, sizeof(Calc_Token) * tokens->cap);
268 | }
269 | tokens->tokens[tokens->len-1] = token;
270 | }
271 |
272 | bool calc_is_op_normal(Calc_Op op) {
273 | switch(op) {
274 | case calc_add:
275 | case calc_sub:
276 | case calc_mul:
277 | case calc_div:
278 | case calc_pow:
279 | case calc_mod:
280 | case calc_to:
281 | case calc_and:
282 | case calc_or:
283 | case calc_not:
284 | case calc_eq_:
285 | case calc_neq:
286 | case calc_lt:
287 | case calc_gt:
288 | case calc_lte:
289 | case calc_gte:
290 | return 1;
291 | default: return 0;
292 | }
293 | }
294 |
295 | static const Calc_Len_Str_Size(1) calc_add_str = {1, '+'};
296 | static const Calc_Len_Str_Size(1) calc_sub_str = {1, '-'};
297 | static const Calc_Len_Str_Size(1) calc_mul_str = {1, '*'};
298 | static const Calc_Len_Str_Size(1) calc_div_str = {1, '/'};
299 | static const Calc_Len_Str_Size(1) calc_pow_str = {1, '^'};
300 | static const Calc_Len_Str_Size(1) calc_mod_str = {1, '%'};
301 | static const Calc_Len_Str_Size(2) calc_to_str = {2, '.', '.'};
302 | static const Calc_Len_Str_Size(1) calc_and_str = {1, '&'};
303 | static const Calc_Len_Str_Size(1) calc_or_str = {1, '|'};
304 | static const Calc_Len_Str_Size(1) calc_not_str = {1, '!'};
305 | static const Calc_Len_Str_Size(1) calc_eq_str = {1, '='};
306 | static const Calc_Len_Str_Size(2) calc_neq_str = {2, '!', '='};
307 | static const Calc_Len_Str_Size(1) calc_lt_str = {1, '<'};
308 | static const Calc_Len_Str_Size(1) calc_gt_str = {1, '>'};
309 | static const Calc_Len_Str_Size(2) calc_lte_str = {2, '<', '='};
310 | static const Calc_Len_Str_Size(2) calc_gte_str = {2, '>', '='};
311 | static const Calc_Len_Str_Size(1) calc_refof_str = {1, '\''};
312 | static const Calc_Len_Str_Size(1) calc_list_start_str = {1, '['};
313 | static const Calc_Len_Str_Size(1) calc_list_end_str = {1, ']'};
314 | static const Calc_Len_Str_Size(1) calc_list_sep_str = {1, ','};
315 | static const Calc_Len_Str_Size(1) calc_func_start_str = {1, '{'};
316 | static const Calc_Len_Str_Size(1) calc_func_end_str = {1, '}'};
317 | static const Calc_Len_Str_Size(2) calc_func_arrow_str = {2, '-', '>'};
318 | static const Calc_Len_Str_Size(2) calc_var_decl_str = {2, ':', '='};
319 | static const Calc_Len_Str_Size(1) calc_var_sep_str = {1, ';'};
320 |
321 | const Calc_Len_Str* calc_op_to_str(Calc_Op op) {
322 | switch(op) {
323 | /* Normal operators. */
324 | case calc_add: return (const Calc_Len_Str*) &calc_add_str;
325 | case calc_sub: return (const Calc_Len_Str*) &calc_sub_str;
326 | case calc_mul: return (const Calc_Len_Str*) &calc_mul_str;
327 | case calc_div: return (const Calc_Len_Str*) &calc_div_str;
328 | case calc_pow: return (const Calc_Len_Str*) &calc_pow_str;
329 | case calc_mod: return (const Calc_Len_Str*) &calc_mod_str;
330 | case calc_to: return (const Calc_Len_Str*) &calc_to_str;
331 | case calc_and: return (const Calc_Len_Str*) &calc_and_str;
332 | case calc_or: return (const Calc_Len_Str*) &calc_or_str;
333 | case calc_not: return (const Calc_Len_Str*) &calc_not_str;
334 | case calc_eq_: return (const Calc_Len_Str*) &calc_eq_str;
335 | case calc_neq: return (const Calc_Len_Str*) &calc_neq_str;
336 | case calc_lt: return (const Calc_Len_Str*) &calc_lt_str;
337 | case calc_gt: return (const Calc_Len_Str*) &calc_gt_str;
338 | case calc_lte: return (const Calc_Len_Str*) &calc_lte_str;
339 | case calc_gte: return (const Calc_Len_Str*) &calc_gte_str;
340 | /* Context operators. */
341 | case calc_refof: return (const Calc_Len_Str*) &calc_refof_str;
342 | case calc_list_start: return (const Calc_Len_Str*) &calc_list_start_str;
343 | case calc_list_end: return (const Calc_Len_Str*) &calc_list_end_str;
344 | case calc_list_sep: return (const Calc_Len_Str*) &calc_list_sep_str;
345 | case calc_func_start: return (const Calc_Len_Str*) &calc_func_start_str;
346 | case calc_func_end: return (const Calc_Len_Str*) &calc_func_end_str;
347 | case calc_func_arrow: return (const Calc_Len_Str*) &calc_func_arrow_str;
348 | case calc_var_decl: return (const Calc_Len_Str*) &calc_var_decl_str;
349 | case calc_var_sep: return (const Calc_Len_Str*) &calc_var_sep_str;
350 | }
351 | }
352 |
353 | /* Clean up. */
354 |
355 | #undef is_digit
356 | #undef is_non_num_op_char
357 | #undef is_num_op_char
358 | #undef is_whitespace
359 |
--------------------------------------------------------------------------------
/C Version/khash.h:
--------------------------------------------------------------------------------
1 | /* The MIT License
2 |
3 | Copyright (c) 2008, 2009, 2011 by Attractive Chaos
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 | */
25 |
26 | /*
27 | An example:
28 |
29 | #include "khash.h"
30 | KHASH_MAP_INIT_INT(32, char)
31 | int main() {
32 | int ret, is_missing;
33 | khiter_t k;
34 | khash_t(32) *h = kh_init(32);
35 | k = kh_put(32, h, 5, &ret);
36 | kh_value(h, k) = 10;
37 | k = kh_get(32, h, 10);
38 | is_missing = (k == kh_end(h));
39 | k = kh_get(32, h, 5);
40 | kh_del(32, h, k);
41 | for (k = kh_begin(h); k != kh_end(h); ++k)
42 | if (kh_exist(h, k)) kh_value(h, k) = 1;
43 | kh_destroy(32, h);
44 | return 0;
45 | }
46 | */
47 |
48 | /*
49 | 2013-05-02 (0.2.8):
50 |
51 | * Use quadratic probing. When the capacity is power of 2, stepping function
52 | i*(i+1)/2 guarantees to traverse each bucket. It is better than double
53 | hashing on cache performance and is more robust than linear probing.
54 |
55 | In theory, double hashing should be more robust than quadratic probing.
56 | However, my implementation is probably not for large hash tables, because
57 | the second hash function is closely tied to the first hash function,
58 | which reduce the effectiveness of double hashing.
59 |
60 | Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
61 |
62 | 2011-12-29 (0.2.7):
63 |
64 | * Minor code clean up; no actual effect.
65 |
66 | 2011-09-16 (0.2.6):
67 |
68 | * The capacity is a power of 2. This seems to dramatically improve the
69 | speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
70 |
71 | - http://code.google.com/p/ulib/
72 | - http://nothings.org/computer/judy/
73 |
74 | * Allow to optionally use linear probing which usually has better
75 | performance for random input. Double hashing is still the default as it
76 | is more robust to certain non-random input.
77 |
78 | * Added Wang's integer hash function (not used by default). This hash
79 | function is more robust to certain non-random input.
80 |
81 | 2011-02-14 (0.2.5):
82 |
83 | * Allow to declare global functions.
84 |
85 | 2009-09-26 (0.2.4):
86 |
87 | * Improve portability
88 |
89 | 2008-09-19 (0.2.3):
90 |
91 | * Corrected the example
92 | * Improved interfaces
93 |
94 | 2008-09-11 (0.2.2):
95 |
96 | * Improved speed a little in kh_put()
97 |
98 | 2008-09-10 (0.2.1):
99 |
100 | * Added kh_clear()
101 | * Fixed a compiling error
102 |
103 | 2008-09-02 (0.2.0):
104 |
105 | * Changed to token concatenation which increases flexibility.
106 |
107 | 2008-08-31 (0.1.2):
108 |
109 | * Fixed a bug in kh_get(), which has not been tested previously.
110 |
111 | 2008-08-31 (0.1.1):
112 |
113 | * Added destructor
114 | */
115 |
116 |
117 | #ifndef __AC_KHASH_H
118 | #define __AC_KHASH_H
119 |
120 | /*!
121 | @header
122 |
123 | Generic hash table library.
124 | */
125 |
126 | #define AC_VERSION_KHASH_H "0.2.8"
127 |
128 | #include
129 | #include
130 | #include
131 |
132 | /* compiler specific configuration */
133 |
134 | #if UINT_MAX == 0xffffffffu
135 | typedef unsigned int khint32_t;
136 | #elif ULONG_MAX == 0xffffffffu
137 | typedef unsigned long khint32_t;
138 | #endif
139 |
140 | #ifndef kh_inline
141 | #ifdef _MSC_VER
142 | #define kh_inline __inline
143 | #else
144 | #define kh_inline inline
145 | #endif
146 | #endif /* kh_inline */
147 |
148 | #ifndef klib_unused
149 | #if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3)
150 | #define klib_unused __attribute__ ((__unused__))
151 | #else
152 | #define klib_unused
153 | #endif
154 | #endif /* klib_unused */
155 |
156 | typedef khint32_t khint_t;
157 | typedef khint_t khiter_t;
158 |
159 | #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
160 | #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
161 | #define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
162 | #define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
163 | #define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
164 | #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
165 | #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
166 |
167 | #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
168 |
169 | #ifndef kroundup32
170 | #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
171 | #endif
172 |
173 | #ifndef kcalloc
174 | #define kcalloc(N,Z) calloc(N,Z)
175 | #endif
176 | #ifndef kmalloc
177 | #define kmalloc(Z) malloc(Z)
178 | #endif
179 | #ifndef krealloc
180 | #define krealloc(P,Z) realloc(P,Z)
181 | #endif
182 | #ifndef kfree
183 | #define kfree(P) free(P)
184 | #endif
185 |
186 | static const double __ac_HASH_UPPER = 0.77;
187 |
188 | #define __KHASH_TYPE(name, khkey_t, khval_t) \
189 | typedef struct kh_##name##_s { \
190 | khint_t n_buckets, size, n_occupied, upper_bound; \
191 | khint32_t *flags; \
192 | khkey_t *keys; \
193 | khval_t *vals; \
194 | } kh_##name##_t;
195 |
196 | #define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
197 | extern kh_##name##_t *kh_init_##name(void); \
198 | extern void kh_destroy_##name(kh_##name##_t *h); \
199 | extern void kh_clear_##name(kh_##name##_t *h); \
200 | extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
201 | extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
202 | extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
203 | extern void kh_del_##name(kh_##name##_t *h, khint_t x);
204 |
205 | #define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
206 | SCOPE kh_##name##_t *kh_init_##name(void) { \
207 | return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
208 | } \
209 | SCOPE void kh_destroy_##name(kh_##name##_t *h) \
210 | { \
211 | if (h) { \
212 | kfree((void *)h->keys); kfree(h->flags); \
213 | kfree((void *)h->vals); \
214 | kfree(h); \
215 | } \
216 | } \
217 | SCOPE void kh_clear_##name(kh_##name##_t *h) \
218 | { \
219 | if (h && h->flags) { \
220 | memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
221 | h->size = h->n_occupied = 0; \
222 | } \
223 | } \
224 | SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
225 | { \
226 | if (h->n_buckets) { \
227 | khint_t k, i, last, mask, step = 0; \
228 | mask = h->n_buckets - 1; \
229 | k = __hash_func(key); i = k & mask; \
230 | last = i; \
231 | while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
232 | i = (i + (++step)) & mask; \
233 | if (i == last) return h->n_buckets; \
234 | } \
235 | return __ac_iseither(h->flags, i)? h->n_buckets : i; \
236 | } else return 0; \
237 | } \
238 | SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
239 | { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
240 | khint32_t *new_flags = 0; \
241 | khint_t j = 1; \
242 | { \
243 | kroundup32(new_n_buckets); \
244 | if (new_n_buckets < 4) new_n_buckets = 4; \
245 | if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
246 | else { /* hash table size to be changed (shrink or expand); rehash */ \
247 | new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
248 | if (!new_flags) return -1; \
249 | memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
250 | if (h->n_buckets < new_n_buckets) { /* expand */ \
251 | khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
252 | if (!new_keys) { kfree(new_flags); return -1; } \
253 | h->keys = new_keys; \
254 | if (kh_is_map) { \
255 | khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
256 | if (!new_vals) { kfree(new_flags); return -1; } \
257 | h->vals = new_vals; \
258 | } \
259 | } /* otherwise shrink */ \
260 | } \
261 | } \
262 | if (j) { /* rehashing is needed */ \
263 | for (j = 0; j != h->n_buckets; ++j) { \
264 | if (__ac_iseither(h->flags, j) == 0) { \
265 | khkey_t key = h->keys[j]; \
266 | khval_t val; \
267 | khint_t new_mask; \
268 | new_mask = new_n_buckets - 1; \
269 | if (kh_is_map) val = h->vals[j]; \
270 | __ac_set_isdel_true(h->flags, j); \
271 | while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
272 | khint_t k, i, step = 0; \
273 | k = __hash_func(key); \
274 | i = k & new_mask; \
275 | while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
276 | __ac_set_isempty_false(new_flags, i); \
277 | if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
278 | { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
279 | if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
280 | __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
281 | } else { /* write the element and jump out of the loop */ \
282 | h->keys[i] = key; \
283 | if (kh_is_map) h->vals[i] = val; \
284 | break; \
285 | } \
286 | } \
287 | } \
288 | } \
289 | if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
290 | h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
291 | if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
292 | } \
293 | kfree(h->flags); /* free the working space */ \
294 | h->flags = new_flags; \
295 | h->n_buckets = new_n_buckets; \
296 | h->n_occupied = h->size; \
297 | h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
298 | } \
299 | return 0; \
300 | } \
301 | SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
302 | { \
303 | khint_t x; \
304 | if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
305 | if (h->n_buckets > (h->size<<1)) { \
306 | if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
307 | *ret = -1; return h->n_buckets; \
308 | } \
309 | } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
310 | *ret = -1; return h->n_buckets; \
311 | } \
312 | } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
313 | { \
314 | khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
315 | x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
316 | if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
317 | else { \
318 | last = i; \
319 | while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
320 | if (__ac_isdel(h->flags, i)) site = i; \
321 | i = (i + (++step)) & mask; \
322 | if (i == last) { x = site; break; } \
323 | } \
324 | if (x == h->n_buckets) { \
325 | if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
326 | else x = i; \
327 | } \
328 | } \
329 | } \
330 | if (__ac_isempty(h->flags, x)) { /* not present at all */ \
331 | h->keys[x] = key; \
332 | __ac_set_isboth_false(h->flags, x); \
333 | ++h->size; ++h->n_occupied; \
334 | *ret = 1; \
335 | } else if (__ac_isdel(h->flags, x)) { /* deleted */ \
336 | h->keys[x] = key; \
337 | __ac_set_isboth_false(h->flags, x); \
338 | ++h->size; \
339 | *ret = 2; \
340 | } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
341 | return x; \
342 | } \
343 | SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
344 | { \
345 | if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
346 | __ac_set_isdel_true(h->flags, x); \
347 | --h->size; \
348 | } \
349 | }
350 |
351 | #define KHASH_DECLARE(name, khkey_t, khval_t) \
352 | __KHASH_TYPE(name, khkey_t, khval_t) \
353 | __KHASH_PROTOTYPES(name, khkey_t, khval_t)
354 |
355 | #define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
356 | __KHASH_TYPE(name, khkey_t, khval_t) \
357 | __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
358 |
359 | #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
360 | KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
361 |
362 | /* --- BEGIN OF HASH FUNCTIONS --- */
363 |
364 | /*! @function
365 | @abstract Integer hash function
366 | @param key The integer [khint32_t]
367 | @return The hash value [khint_t]
368 | */
369 | #define kh_int_hash_func(key) (khint32_t)(key)
370 | /*! @function
371 | @abstract Integer comparison function
372 | */
373 | #define kh_int_hash_equal(a, b) ((a) == (b))
374 | /*! @function
375 | @abstract const char* hash function
376 | @param s Pointer to a null terminated string
377 | @return The hash value
378 | */
379 | static kh_inline khint_t __ac_X31_hash_string(const char *s)
380 | {
381 | khint_t h = (khint_t)*s;
382 | if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
383 | return h;
384 | }
385 | /*! @function
386 | @abstract Another interface to const char* hash function
387 | @param key Pointer to a null terminated string [const char*]
388 | @return The hash value [khint_t]
389 | */
390 | #define kh_str_hash_func(key) __ac_X31_hash_string(key)
391 | /*! @function
392 | @abstract Const char* comparison function
393 | */
394 | #define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
395 |
396 | static kh_inline khint_t __ac_Wang_hash(khint_t key)
397 | {
398 | key += ~(key << 15);
399 | key ^= (key >> 10);
400 | key += (key << 3);
401 | key ^= (key >> 6);
402 | key += ~(key << 11);
403 | key ^= (key >> 16);
404 | return key;
405 | }
406 | #define kh_int_hash_func2(key) __ac_Wang_hash((khint_t)key)
407 |
408 | /* --- END OF HASH FUNCTIONS --- */
409 |
410 | /* Other convenient macros... */
411 |
412 | /*!
413 | @abstract Type of the hash table.
414 | @param name Name of the hash table [symbol]
415 | */
416 | #define khash_t(name) kh_##name##_t
417 |
418 | /*! @function
419 | @abstract Initiate a hash table.
420 | @param name Name of the hash table [symbol]
421 | @return Pointer to the hash table [khash_t(name)*]
422 | */
423 | #define kh_init(name) kh_init_##name()
424 |
425 | /*! @function
426 | @abstract Destroy a hash table.
427 | @param name Name of the hash table [symbol]
428 | @param h Pointer to the hash table [khash_t(name)*]
429 | */
430 | #define kh_destroy(name, h) kh_destroy_##name(h)
431 |
432 | /*! @function
433 | @abstract Reset a hash table without deallocating memory.
434 | @param name Name of the hash table [symbol]
435 | @param h Pointer to the hash table [khash_t(name)*]
436 | */
437 | #define kh_clear(name, h) kh_clear_##name(h)
438 |
439 | /*! @function
440 | @abstract Resize a hash table.
441 | @param name Name of the hash table [symbol]
442 | @param h Pointer to the hash table [khash_t(name)*]
443 | @param s New size [khint_t]
444 | */
445 | #define kh_resize(name, h, s) kh_resize_##name(h, s)
446 |
447 | /*! @function
448 | @abstract Insert a key to the hash table.
449 | @param name Name of the hash table [symbol]
450 | @param h Pointer to the hash table [khash_t(name)*]
451 | @param k Key [type of keys]
452 | @param r Extra return code: -1 if the operation failed;
453 | 0 if the key is present in the hash table;
454 | 1 if the bucket is empty (never used); 2 if the element in
455 | the bucket has been deleted [int*]
456 | @return Iterator to the inserted element [khint_t]
457 | */
458 | #define kh_put(name, h, k, r) kh_put_##name(h, k, r)
459 |
460 | /*! @function
461 | @abstract Retrieve a key from the hash table.
462 | @param name Name of the hash table [symbol]
463 | @param h Pointer to the hash table [khash_t(name)*]
464 | @param k Key [type of keys]
465 | @return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
466 | */
467 | #define kh_get(name, h, k) kh_get_##name(h, k)
468 |
469 | /*! @function
470 | @abstract Remove a key from the hash table.
471 | @param name Name of the hash table [symbol]
472 | @param h Pointer to the hash table [khash_t(name)*]
473 | @param k Iterator to the element to be deleted [khint_t]
474 | */
475 | #define kh_del(name, h, k) kh_del_##name(h, k)
476 |
477 | /*! @function
478 | @abstract Test whether a bucket contains data.
479 | @param h Pointer to the hash table [khash_t(name)*]
480 | @param x Iterator to the bucket [khint_t]
481 | @return 1 if containing data; 0 otherwise [int]
482 | */
483 | #define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
484 |
485 | /*! @function
486 | @abstract Get key given an iterator
487 | @param h Pointer to the hash table [khash_t(name)*]
488 | @param x Iterator to the bucket [khint_t]
489 | @return Key [type of keys]
490 | */
491 | #define kh_key(h, x) ((h)->keys[x])
492 |
493 | /*! @function
494 | @abstract Get value given an iterator
495 | @param h Pointer to the hash table [khash_t(name)*]
496 | @param x Iterator to the bucket [khint_t]
497 | @return Value [type of values]
498 | @discussion For hash sets, calling this results in segfault.
499 | */
500 | #define kh_val(h, x) ((h)->vals[x])
501 |
502 | /*! @function
503 | @abstract Alias of kh_val()
504 | */
505 | #define kh_value(h, x) ((h)->vals[x])
506 |
507 | /*! @function
508 | @abstract Get the start iterator
509 | @param h Pointer to the hash table [khash_t(name)*]
510 | @return The start iterator [khint_t]
511 | */
512 | #define kh_begin(h) (khint_t)(0)
513 |
514 | /*! @function
515 | @abstract Get the end iterator
516 | @param h Pointer to the hash table [khash_t(name)*]
517 | @return The end iterator [khint_t]
518 | */
519 | #define kh_end(h) ((h)->n_buckets)
520 |
521 | /*! @function
522 | @abstract Get the number of elements in the hash table
523 | @param h Pointer to the hash table [khash_t(name)*]
524 | @return Number of elements in the hash table [khint_t]
525 | */
526 | #define kh_size(h) ((h)->size)
527 |
528 | /*! @function
529 | @abstract Get the number of buckets in the hash table
530 | @param h Pointer to the hash table [khash_t(name)*]
531 | @return Number of buckets in the hash table [khint_t]
532 | */
533 | #define kh_n_buckets(h) ((h)->n_buckets)
534 |
535 | /*! @function
536 | @abstract Iterate over the entries in the hash table
537 | @param h Pointer to the hash table [khash_t(name)*]
538 | @param kvar Variable to which key will be assigned
539 | @param vvar Variable to which value will be assigned
540 | @param code Block of code to execute
541 | */
542 | #define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
543 | for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
544 | if (!kh_exist(h,__i)) continue; \
545 | (kvar) = kh_key(h,__i); \
546 | (vvar) = kh_val(h,__i); \
547 | code; \
548 | } }
549 |
550 | /*! @function
551 | @abstract Iterate over the values in the hash table
552 | @param h Pointer to the hash table [khash_t(name)*]
553 | @param vvar Variable to which value will be assigned
554 | @param code Block of code to execute
555 | */
556 | #define kh_foreach_value(h, vvar, code) { khint_t __i; \
557 | for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
558 | if (!kh_exist(h,__i)) continue; \
559 | (vvar) = kh_val(h,__i); \
560 | code; \
561 | } }
562 |
563 | /* More convenient interfaces */
564 |
565 | /*! @function
566 | @abstract Instantiate a hash set containing integer keys
567 | @param name Name of the hash table [symbol]
568 | */
569 | #define KHASH_SET_INIT_INT(name) \
570 | KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
571 |
572 | /*! @function
573 | @abstract Instantiate a hash map containing integer keys
574 | @param name Name of the hash table [symbol]
575 | @param khval_t Type of values [type]
576 | */
577 | #define KHASH_MAP_INIT_INT(name, khval_t) \
578 | KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
579 |
580 | typedef const char *kh_cstr_t;
581 | /*! @function
582 | @abstract Instantiate a hash map containing const char* keys
583 | @param name Name of the hash table [symbol]
584 | */
585 | #define KHASH_SET_INIT_STR(name) \
586 | KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
587 |
588 | /*! @function
589 | @abstract Instantiate a hash map containing const char* keys
590 | @param name Name of the hash table [symbol]
591 | @param khval_t Type of values [type]
592 | */
593 | #define KHASH_MAP_INIT_STR(name, khval_t) \
594 | KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
595 |
596 | #endif /* __AC_KHASH_H */
597 |
--------------------------------------------------------------------------------
/calc/standard library.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var types = require("./types");
4 | var print = require("./print");
5 | var run_part = require("./run part");
6 | var variable_manipulation = require("./variable manipulation");
7 | var help = require("./help");
8 |
9 | function assert_stack_size(stack, len, func) {
10 | if(stack.length < len) {
11 | throw `Error: ${func.is_func ? "function" : "operator"} "${func.name}" expected the stack to contain at least ${len} items, but it contained ${stack.length}.`;
12 | }
13 | }
14 |
15 | // Generate built-ins based on a stack, operators, and an end time.
16 |
17 | function built_ins(stack, calc, operators, end_time) {
18 | var made_built_ins = expand({
19 |
20 | // Help functions.
21 |
22 | "help, h"() {
23 | stack.push(types.new_str(help.help_menu));
24 | },
25 | "page, help_page, hp, h_page, help_p, doc, docs, documentation"() {
26 | if(stack.length == 0) {
27 | stack.push(types.new_str(help.page_index));
28 | } else {
29 | var page = stack.pop();
30 | if(page.type == types.str) {
31 | var found = help.page_categories[page.data];
32 | if(found) {
33 | stack.push(types.new_str(found));
34 | } else {
35 | stack.push(type.new_str(`Error: "${page.data}" is not a category.`));
36 | }
37 | } else if(page.type == types.sym) {
38 | var found = made_built_ins[page.data];
39 | if(found) {
40 | stack.push(types.new_str(
41 | help.help_pages[found.main_alias](found.aliases.join(", "))
42 | ));
43 | } else {
44 | stack.push(types.new_str(`Error: "${page.data}" is not a built-in.`));
45 | }
46 | } else if(page.type == types.op) {
47 | stack.push(types.new_str(help.op_help_pages[page.data]));
48 | } else {
49 | stack.push(types.new_str(`Error: cannot get help page for value "${print(page)}" of type ${types.type_to_str(page.type)}.`));
50 | }
51 | }
52 | },
53 | "tut, tutorial"() {
54 | if(stack.length == 0) {
55 | stack.push(types.new_str(help.tut_pages[0]));
56 | } else {
57 | var page = stack.pop().data;
58 | if(page < help.tut_pages.length) {
59 | stack.push(types.new_str(help.tut_pages[page]));
60 | } else {
61 | stack.push(types.new_str(`Error: tutorial page ${page} does not exist.`));
62 | }
63 | }
64 | },
65 | "adv_tut, adv_tutorial, advanced_tutorial, advanced_tut"() {
66 | if(stack.length == 0) {
67 | stack.push(types.new_str(help.adv_tut_pages[0]));
68 | } else {
69 | var page = stack.pop().data;
70 | if(page < help.adv_tut_pages.length) {
71 | stack.push(types.new_str(help.adv_tut_pages[page]));
72 | } else {
73 | stack.push(types.new_str(`Error: advanced tutorial page ${page} does not exist.`));
74 | }
75 | }
76 | },
77 |
78 | // Basic functions.
79 |
80 | "type, typeof, instance, instanceof"() {
81 | stack.push(types.new_str(types.type_to_str(stack.pop().type)));
82 | },
83 | "true, yes, on"() {
84 | stack.push(types.new_bool(true));
85 | },
86 | "false, no, off"() {
87 | stack.push(types.new_bool(false));
88 | },
89 | "num_to_str, number_to_string"() {
90 | var num = stack.pop().data;
91 | stack.push(types.new_str((Math.round(num * 100000) / 100000).toString()));
92 | },
93 | "str_to_num, string_to_number"() {
94 | var str = stack.pop().data;
95 | stack.push(types.new_num(parseFloat(str)));
96 | },
97 | "eval, evaluate, calc"() {
98 | var program = stack.pop().data;
99 | stack.push(types.new_list(
100 | calc(program, end_time - (new Date).getTime())
101 | ));
102 | },
103 |
104 | // Flow control.
105 |
106 | "if, iff"() {
107 | var if_false = stack.pop();
108 | var if_true = stack.pop();
109 | var cond = stack.pop();
110 |
111 | if(types.to_bool(cond)) {
112 | run_part.run_function(if_true, stack, made_built_ins, operators, end_time);
113 | } else {
114 | run_part.run_function(if_false, stack, made_built_ins, operators, end_time);
115 | }
116 | },
117 |
118 | // Stack functions.
119 |
120 | "dup, duplicate"() {
121 | stack.push(stack[stack.length - 1]);
122 | },
123 | swap() {
124 | var first = stack.pop();
125 | var second = stack.pop();
126 | stack.push(first);
127 | stack.push(second);
128 | },
129 | "stack_reverse_n, stack_invert_n"() {
130 | var n = stack.pop().data;
131 | var reversed_vals = stack.splice(stack.length - n, n).reverse();
132 | stack.push.apply(stack, reversed_vals);
133 | },
134 | "drop, stack_pop"() {
135 | stack.pop();
136 | },
137 | "dropn, stack_pop_n"() {
138 | var n = stack.pop().data;
139 | for(let cou = 0; cou < n; cou++) {
140 | stack.pop();
141 | }
142 | },
143 | "rot, rotate"() {
144 | var first = stack.pop();
145 | var second = stack.pop();
146 | var third = stack.pop();
147 | stack.push(first);
148 | stack.push(third);
149 | stack.push(second);
150 | },
151 | "unrot, unrotate, reverse_rot, reverse_rotate, counter_rot, counter_rotate"() {
152 | var first = stack.pop();
153 | var second = stack.pop();
154 | var third = stack.pop();
155 | stack.push(second);
156 | stack.push(first);
157 | stack.push(third);
158 | },
159 | "roll, rot_n, rotate_n"() {
160 | var n = stack.pop().data;
161 |
162 | if(n > 0) {
163 | var rolled = stack.pop();
164 | stack.splice(stack.length - n + 1, 0, rolled);
165 | } else {
166 | var rolled = stack[stack.length + n];
167 | stack.splice(stack.length + n, 1);
168 | stack.push(rolled);
169 | }
170 | },
171 | "unroll, unrot_n, unrotate_n, reverse_roll, counter_roll, reverse_rot_n, reverse_rotate_n, counter_rot_n, counter_rotate_n"() {
172 | var n = stack.pop().data;
173 |
174 | if(n > 0) {
175 | var rolled = stack[stack.length - n];
176 | stack.splice(stack.length - n, 1);
177 | stack.push(rolled);
178 | } else {
179 | var rolled = stack.pop();
180 | stack.splice(stack.length + n + 1, 0, rolled);
181 | }
182 | },
183 | nip() {
184 | var first = stack.pop();
185 | var second = stack.pop();
186 | stack.push(first);
187 | },
188 | tuck() {
189 | var first = stack.pop();
190 | var second = stack.pop();
191 | stack.push(first);
192 | stack.push(second);
193 | stack.push(first);
194 | },
195 | over() {
196 | var first = stack.pop();
197 | var second = stack.pop();
198 | stack.push(second);
199 | stack.push(first);
200 | stack.push(second);
201 | },
202 |
203 | // List functions.
204 |
205 | "map, fmap"() {
206 | var mapper = stack.pop();
207 | var list = stack.pop().data;
208 |
209 | var mapped = list.map(item => {
210 | stack.push(item);
211 | run_part.run_function(mapper, stack, made_built_ins, operators, end_time);
212 | return stack.pop();
213 | });
214 |
215 | stack.push(types.new_list(mapped));
216 | },
217 | "fold, foldl, reduce, fold_left"() {
218 | var reducer = stack.pop();
219 | var accumulator = stack.pop();
220 | var list = stack.pop().data;
221 | stack.push(accumulator);
222 |
223 | for(let cou = 0; cou < list.length; cou++) {
224 | stack.push(list[cou]);
225 | run_part.run_function(reducer, stack, made_built_ins, operators, end_time);
226 | }
227 | },
228 | "foldr, fold_right"() {
229 | var reducer = stack.pop();
230 | var accumulator = stack.pop();
231 | var list = stack.pop().data;
232 | stack.push(accumulator);
233 |
234 | for(let cou = list.length - 1; cou > -1; cou--) {
235 | stack.push(list[cou]);
236 | run_part.run_function(reducer, stack, made_built_ins, operators, end_time);
237 | }
238 | },
239 | filter() {
240 | var filter = stack.pop();
241 | var list = stack.pop().data;
242 |
243 | var filtered = list.filter(item => {
244 | stack.push(item);
245 | run_part.run_function(filter, stack, made_built_ins, operators, end_time);
246 | return types.to_bool(stack.pop());
247 | });
248 |
249 | stack.push(types.new_list(filtered));
250 | },
251 | "length, size, len"() {
252 | stack.push(types.new_num(stack.pop().data.length));
253 | },
254 | "head, first, cat, top, pop, fst"() {
255 | var list = stack.pop().data;
256 | stack.push(list[0]);
257 | },
258 | "snd, second"() {
259 | var list = stack.pop().data;
260 | stack.push(list[1]);
261 | },
262 | "last, bottom"() {
263 | var list = stack.pop().data;
264 | stack.push(list[list.length - 1]);
265 | },
266 | "back_snd, back_second, before_last"() {
267 | var list = stack.pop().data;
268 | stack.push(list[list.length - 2]);
269 | },
270 | "nth, item, front_n, index, front_index, middle_n, middle_index"() {
271 | var index = stack.pop().data;
272 | var list = stack.pop().data;
273 | stack.push(list[index]);
274 | },
275 | "back_nth, back_item, last_n, back_n, back_index"() {
276 | var index = stack.pop().data;
277 | var list = stack.pop().data;
278 | stack.push(list[list.length - index - 1]);
279 | },
280 | "init, front, list_drop"() {
281 | stack.push(types.new_list(stack.pop().data.slice(0, -1)));
282 | },
283 | "tail, back, cdr, rest"() {
284 | stack.push(types.new_list(stack.pop().data.slice(1)));
285 | },
286 | "body, middle"() {
287 | stack.push(types.new_list(stack.pop().data.slice(1, -1)));
288 | },
289 | "reverse, invert"() {
290 | var list = stack.pop().data;
291 | stack.push(types.new_list(list.reverse()));
292 | },
293 | "reverse_n, invert_n"() {
294 | var n = stack.pop().data;
295 | var list = stack.pop().data;
296 | list = list.concat(list.splice(list.length - n, n).reverse());
297 | stack.push(types.new_list(list));
298 | },
299 | "pop_n, list_drop_n"() {
300 | var n = stack.pop().data;
301 | var list = stack.pop().data;
302 | for(let cou = 0; cou < n; cou++) {
303 | list.pop();
304 | }
305 | stack.push(types.new_list(list));
306 | },
307 | "elem, includes, contains, in_list"() {
308 | var item = stack.pop();
309 | var list = stack.pop().data;
310 |
311 | stack.push(types.new_bool(list.reduce(
312 | (acc, cur) => acc || types.eq(item, cur),
313 | false
314 | )));
315 | },
316 | join() {
317 | var joiner = stack.pop().data;
318 | var list = stack.pop().data.map(str => str.data);
319 | stack.push(types.new_str(list.join(joiner)));
320 | },
321 | split() {
322 | var splitter = stack.pop().data;
323 | var string = stack.pop().data;
324 | stack.push(types.new_list(
325 | string.split(splitter).map(part => types.new_str(part))
326 | ));
327 | },
328 | "expl, explode, extr, extract, spr, spread"() {
329 | var list = stack.pop().data;
330 | for(let cou = 0; cou < list.length; cou++) {
331 | stack.push(list[cou]);
332 | }
333 | },
334 | "group, as_list"() {
335 | var n = stack.pop().data;
336 |
337 | var list = [];
338 | for(let cou = 0; cou < n; cou++) {
339 | list.unshift(stack.pop());
340 | }
341 | stack.push(types.new_list(list));
342 | },
343 | "copy_group, copy_as_list"() {
344 | var n = stack.pop().data;
345 |
346 | var list = [];
347 | for(let cou = 0; cou < n; cou++) {
348 | list.unshift(stack[stack.length - 1 - cou]);
349 | }
350 | stack.push(types.new_list(list));
351 | },
352 | "box, singleton"() {
353 | stack.push(types.new_list([stack.pop()]));
354 | },
355 | "copy_box, copy_singleton"() {
356 | stack.push(types.new_list([stack[stack.length - 1]]));
357 | },
358 | group_all() {
359 | var list = stack.slice();
360 | stack.splice(0, stack.length);
361 | stack.push(types.new_list(list));
362 | },
363 | copy_group_all() {
364 | var list = stack.slice();
365 | stack.push(types.new_list(list));
366 | },
367 | "list_dup, list_duplicate"() {
368 | var list = stack.pop().data;
369 | list.push(list[list.length - 1]);
370 | stack.push(types.new_list(list));
371 | },
372 | list_swap() {
373 | var list = stack.pop().data;
374 | var first = list.pop();
375 | var second = list.pop();
376 | list.push(first);
377 | list.push(second);
378 | stack.push(types.new_list(list));
379 | },
380 | "list_rot, list_rotate"() {
381 | var list = stack.pop().data;
382 | var first = list.pop();
383 | var second = list.pop();
384 | var third = list.pop();
385 | list.push(first);
386 | list.push(third);
387 | list.push(second);
388 | stack.push(types.new_list(list));
389 | },
390 | "list_unrot, list_unrotate, list_reverse_rot, list_reverse_rotate, list_counter_rot, list_counter_rotate"() {
391 | var list = stack.pop().data;
392 | var first = list.pop();
393 | var second = list.pop();
394 | var third = list.pop();
395 | list.push(second);
396 | list.push(first);
397 | list.push(third);
398 | stack.push(types.new_list(list));
399 | },
400 | "list_roll, list_rot_n, list_rotate_n"() {
401 | var n = stack.pop().data;
402 | var list = stack.pop().data;
403 |
404 | if(n > 0) {
405 | var rolled = list.pop();
406 | list.splice(list.length - n + 1, 0, rolled);
407 | } else {
408 | var rolled = list[list.length + n];
409 | list.splice(list.length + n, 1);
410 | list.push(rolled);
411 | }
412 |
413 | stack.push(types.new_list(list));
414 | },
415 | "list_unroll, list_reverse_roll, list_counter_roll, list_reverse_rot_n, list_reverse_rotate_n, list_counter_rot_n, list_counter_rotate_n"() {
416 | var n = stack.pop().data;
417 | var list = stack.pop().data;
418 |
419 | if(n > 0) {
420 | var rolled = list[list.length - n];
421 | list.splice(list.length - n, 1);
422 | list.push(rolled);
423 | } else {
424 | var rolled = list.pop();
425 | list.splice(list.length + n + 1, 0, rolled);
426 | }
427 |
428 | stack.push(types.new_list(list));
429 | },
430 | list_nip() {
431 | var list = stack.pop().data;
432 | var first = list.pop();
433 | var second = list.pop();
434 | list.push(first);
435 | stack.push(types.new_list(list));
436 | },
437 | list_tuck() {
438 | var list = stack.pop().data;
439 | var first = list.pop();
440 | var second = list.pop();
441 | list.push(first);
442 | list.push(second);
443 | list.push(first);
444 | stack.push(types.new_list(list));
445 | },
446 | list_over() {
447 | var list = stack.pop().data;
448 | var first = list.pop();
449 | var second = list.pop();
450 | list.push(second);
451 | list.push(first);
452 | list.push(second);
453 | stack.push(types.new_list(list));
454 | },
455 |
456 | // Math functions.
457 |
458 | pi() {
459 | stack.push(types.new_num(Math.PI));
460 | },
461 | tau() {
462 | stack.push(types.new_num(Math.PI * 2));
463 | },
464 | e() {
465 | stack.push(types.new_num(Math.E));
466 | },
467 | "abs, absolute, positive"() {
468 | stack.push(types.new_num(Math.abs(stack.pop().data)));
469 | },
470 | "round, trunc, truncate"() {
471 | stack.push(types.new_num(Math.round(stack.pop().data)));
472 | },
473 | "ceil, ceiling, roof, round_up, round_upwards"() {
474 | stack.push(types.new_num(Math.ceil(stack.pop().data)));
475 | },
476 | "floor, round_down, round_downwards"() {
477 | stack.push(types.new_num(Math.floor(stack.pop().data)));
478 | },
479 | "max, maximum, biggest, longest, largest"() {
480 | var right = stack.pop();
481 | var left = stack.pop();
482 | stack.push(types.cmp(left, right, (x, y) => x > y) ? left : right);
483 | },
484 | "min, minimum, smallest, shortest"() {
485 | var right = stack.pop();
486 | var left = stack.pop();
487 | stack.push(types.cmp(left, right, (x, y) => x < y) ? left : right);
488 | },
489 | "sgn, sign"() {
490 | stack.push(types.new_num(Math.sign(stack.pop().data)));
491 | },
492 | "evn, even"() {
493 | stack.push(types.new_num(stack.pop().data % 2 == 0));
494 | },
495 | odd() {
496 | stack.push(types.new_num(Math.abs(stack.pop().data % 2) == 1));
497 | },
498 | "rand, random"() {
499 | var max = stack.pop().data;
500 | var min = stack.pop().data;
501 | stack.push(types.new_num((Math.random() * (max - min)) + min));
502 | },
503 | "cos, cosine"() {
504 | stack.push(types.new_num(Math.cos(stack.pop().data)));
505 | },
506 | "sin, sine"() {
507 | stack.push(types.new_num(Math.sin(stack.pop().data)));
508 | },
509 | "tan, tangent"() {
510 | stack.push(types.new_num(Math.tan(stack.pop().data)));
511 | },
512 | "sec, secant"() {
513 | stack.push(types.new_num(1 / Math.cos(stack.pop().data)));
514 | },
515 | "csc, cosecant"() {
516 | stack.push(types.new_num(1 / Math.sin(stack.pop().data)));
517 | },
518 | "cot, cotangent"() {
519 | stack.push(types.new_num(1 / Math.tan(stack.pop().data)));
520 | },
521 | "sqrt, square_root"() {
522 | stack.push(types.new_num(Math.sqrt(stack.pop().data)));
523 | },
524 | "cbrt, cube_root"() {
525 | stack.push(types.new_num(Math.cbrt(stack.pop().data)));
526 | },
527 | "root, nth_root"() {
528 | var exp = stack.pop().data;
529 | var num = stack.pop().data;
530 | stack.push(types.new_num(num ** (1 / exp)));
531 | },
532 | "log, logarithm, log_n"() {
533 | var base = stack.pop().data;
534 | var num = stack.pop().data;
535 | stack.push(types.new_num(Math.log(num) / Math.log(base)));
536 | },
537 | "ln, log_e, natural_log, natural_logarithm"() {
538 | stack.push(types.new_num(Math.log(stack.pop().data)));
539 | },
540 |
541 | // Function functions.
542 |
543 | "call, run, do, apply, get, exe, execute"() {
544 | run_part.run_function(stack.pop(), stack, made_built_ins, operators, end_time);
545 | },
546 | "iter, iterate, iterative, loop, loop_n"() {
547 | var iter_cou = stack.pop().data;
548 | var iterator = stack.pop();
549 |
550 | for(let cou = 0; cou < iter_cou; cou++) {
551 | run_part.run_function(iterator, stack, made_built_ins, operators, end_time);
552 | }
553 | },
554 | "id, identity, nop, noop"() {},
555 | "comp, compose"(scopes) {
556 | var comp = {
557 | args: ["f", "g"], variables: [],
558 | data: [{
559 | args: [], variables: [],
560 | data: [types.new_sym("f"), types.new_sym("g")],
561 | type: types.func
562 | }],
563 | type: types.func,
564 | scopes: [{}]
565 | };
566 |
567 | run_part.run_function(comp, stack, made_built_ins, operators, end_time);
568 | },
569 |
570 | // State functions.
571 |
572 | set(scopes) {
573 | var value = stack.pop();
574 | var name = stack.pop().name;
575 | variable_manipulation.set_variable(name, value, scopes);
576 | },
577 | "inc, increment"(scopes) {
578 | var name = stack.pop().name;
579 | var value = variable_manipulation.get_variable(name, scopes);
580 | value.data++;
581 | variable_manipulation.set_variable(name, value, scopes);
582 | },
583 | "dec, decrement"(scopes) {
584 | var name = stack.pop().name;
585 | var value = variable_manipulation.get_variable(name, scopes);
586 | value.data--;
587 | variable_manipulation.set_variable(name, value, scopes);
588 | }
589 | });
590 |
591 | return made_built_ins;
592 | }
593 |
594 | // Generate operators based on a stack.
595 |
596 | function operators(stack) {
597 | return {
598 |
599 | "+"() {
600 | assert_stack_size(stack, 2, {name: "+", is_func: false});
601 |
602 | var right = stack.pop();
603 | var left = stack.pop();
604 |
605 | if(
606 | types.is_num(left) && types.is_num(right) ||
607 | types.is_str(left) && types.is_str(right)
608 | ) {
609 | stack.push({
610 | data: left.data + right.data,
611 | type: left.type
612 | });
613 | } else if(types.is_list(left) && !types.is_list(right)) {
614 | stack.push(types.new_list([...left.data, right]));
615 | } else if(!types.is_list(left) && types.is_list(right)) {
616 | stack.push(types.new_list([left, ...right.data]));
617 | } else if(types.is_list(left) && types.is_list(right)) {
618 | stack.push(types.new_list([...left.data, ...right.data]));
619 | } else {
620 | throw `Error: incorrect argument types for "+", please use "calc= $+ page" to read the documentation.`;
621 | }
622 | },
623 | "-"() {
624 | assert_stack_size(stack, 2, {name: "-", is_func: false});
625 |
626 | var right = stack.pop();
627 | var left = stack.pop();
628 |
629 | if(types.is_num(left) && types.is_num(right)) {
630 | stack.push({
631 | data: left.data - right.data,
632 | type: types.num
633 | });
634 | } else if(types.is_list_like(left) && types.is_num(right)) {
635 | var cut_list_like = right.data > 0
636 | ? left.data.slice(0, -right.data)
637 | : (right.data < 0
638 | ? left.data.slice(-right.data)
639 | : left.data);
640 | stack.push({data: cut_list_like, type: left.type});
641 | }
642 | },
643 | "*"() {
644 | assert_stack_size(stack, 2, {name: "*", is_func: false});
645 |
646 | var right = stack.pop();
647 | var left = stack.pop();
648 |
649 | var list_repeat = (list, num) => Array(num).fill(list).flat();
650 | var cartesian_prod = (col, row) => col.reduce(
651 | (acc, i) => [...acc, ...row.map(j => [i, j])],
652 | []
653 | );
654 |
655 | if(types.is_num(left) && types.is_num(right)) {
656 | stack.push(types.new_num(left.data * right.data));
657 | } else if(types.is_list(left) && types.is_num(right)) {
658 | stack.push(types.new_list(list_repeat(left.data, right.data)));
659 | } else if(types.is_num(left) && types.is_list(right)) {
660 | stack.push(types.new_list(list_repeat(right.data, left.data)));
661 | } else if(types.is_str(left) && types.is_num(right)) {
662 | stack.push(types.new_str(left.data.repeat(right.data)));
663 | } else if(types.is_num(left) && types.is_str(right)) {
664 | stack.push(types.new_str(right.data.repeat(left.data)));
665 | } else if(types.is_str(left) && types.is_str(right)) {
666 | var prod = cartesian_prod(left.data.split(""), right.data.split(""));
667 | stack.push(types.new_list(prod.map(
668 | pair => types.new_str(pair.join(""))
669 | )));
670 | } else if(types.is_list_like(left) && types.is_list_like(right)) {
671 | var list_left = types.is_list(left)
672 | ? left.data
673 | : left.data.split("").map(char => types.new_str(char));
674 | var list_right = types.is_list(right)
675 | ? right.data
676 | : right.data.split("").map(char => types.new_str(char));
677 | var prod = cartesian_prod(list_left, list_right);
678 | stack.push(types.new_list(prod.map(
679 | pair => types.new_list(pair)
680 | )));
681 | }
682 | },
683 | "/"() {
684 | assert_stack_size(stack, 2, {name: "/", is_func: false});
685 |
686 | var right = stack.pop();
687 | var left = stack.pop();
688 |
689 | if(types.is_num(left) && types.is_num(right)) {
690 | stack.push(types.new_num(left.data / right.data));
691 | }
692 | },
693 | "^"() {
694 | assert_stack_size(stack, 2, {name: "^", is_func: false});
695 |
696 | var right = stack.pop();
697 | var left = stack.pop();
698 |
699 | if(types.is_num(left) && types.is_num(right)) {
700 | stack.push(types.new_num(left.data ** right.data));
701 | }
702 | },
703 | "%"() {
704 | assert_stack_size(stack, 2, {name: "^", is_func: false});
705 |
706 | var right = stack.pop();
707 | var left = stack.pop();
708 |
709 | if(types.is_num(left) && types.is_num(right)) {
710 | stack.push(types.new_num(left.data % right.data));
711 | }
712 | },
713 | ".."() {
714 | assert_stack_size(stack, 2, {name: "..", is_func: false});
715 |
716 | var right = stack.pop();
717 | var left = stack.pop();
718 |
719 | if(types.is_num(left) && types.is_num(right)) {
720 | var beginning = Math.floor(left.data);
721 | var end = Math.floor(right.data);
722 | } else if(types.is_str(left) && types.is_str(right)) {
723 | if(left.data.length != 1 || right.data.length != 1) {
724 | throw `Error: ".." found the strings "${left.data}" of length ${left.data.length} and "${right.data}" of length ${right.data.length}. ".." expected both to be length 1 (characters).`;
725 | }
726 |
727 | var beginning = left.data.charCodeAt();
728 | var end = right.data.charCodeAt();
729 | } else {
730 | throw `Error: ".." expected two numbers or two strings, instead found a ${types.type_to_str(left.type)} "${print(left)}" and a ${types.type_to_str(right.type)} "${print(right)}".`
731 | }
732 |
733 | var gets_bigger = beginning < end;
734 |
735 | var list = [];
736 | for(
737 | let cou = (gets_bigger ? beginning : end);
738 | cou < (gets_bigger ? end + 1 : beginning + 1);
739 | cou++
740 | ) {
741 | list.push(types.new_num(cou));
742 | }
743 |
744 | if(types.is_str(left)) {
745 | list = list.map(
746 | n => types.new_str(String.fromCharCode(n.data))
747 | );
748 | }
749 | stack.push(types.new_list(gets_bigger ? list : list.reverse()));
750 | },
751 | "&"() {
752 | assert_stack_size(stack, 2, {name: "&", is_func: false});
753 |
754 | var right = stack.pop();
755 | var left = stack.pop();
756 |
757 | if(types.is_num(left) && types.is_num(right)) {
758 | stack.push(types.new_bool(left.data && right.data));
759 | }
760 | },
761 | "|"() {
762 | assert_stack_size(stack, 2, {name: "|", is_func: false});
763 |
764 | var right = stack.pop();
765 | var left = stack.pop();
766 |
767 | if(types.is_num(left) && types.is_num(right)) {
768 | stack.push(types.new_bool(left.data || right.data));
769 | }
770 | },
771 | "!"() {
772 | assert_stack_size(stack, 1, {name: "!", is_func: false});
773 |
774 | var bool = stack.pop();
775 | if(types.is_num(bool)) {
776 | stack.push(types.new_bool(!bool.data));
777 | }
778 | },
779 | "="() {
780 | assert_stack_size(stack, 2, {name: "=", is_func: false});
781 |
782 | var right = stack.pop();
783 | var left = stack.pop();
784 | stack.push(types.new_bool(types.eq(left, right)));
785 | },
786 | "!="() {
787 | assert_stack_size(stack, 2, {name: "!=", is_func: false});
788 |
789 | var right = stack.pop();
790 | var left = stack.pop();
791 | stack.push(types.new_bool(!types.eq(left, right)));
792 | },
793 | "<"() {
794 | assert_stack_size(stack, 2, {name: "<", is_func: false});
795 |
796 | var right = stack.pop();
797 | var left = stack.pop();
798 | stack.push(types.new_bool(types.cmp(left, right, (x, y) => x < y)));
799 | },
800 | ">"() {
801 | assert_stack_size(stack, 2, {name: ">", is_func: false});
802 |
803 | var right = stack.pop();
804 | var left = stack.pop();
805 | stack.push(types.new_bool(types.cmp(left, right, (x, y) => x > y)));
806 | },
807 | "<="() {
808 | assert_stack_size(stack, 2, {name: "<=", is_func: false});
809 |
810 | var right = stack.pop();
811 | var left = stack.pop();
812 | stack.push(types.new_bool(types.cmp(left, right, (x, y) => x <= y)));
813 | },
814 | ">="() {
815 | assert_stack_size(stack, 2, {name: ">=", is_func: false});
816 |
817 | var right = stack.pop();
818 | var left = stack.pop();
819 | stack.push(types.new_bool(types.cmp(left, right, (x, y) => x >= y)));
820 | },
821 | $() {
822 | throw "Error: tried to call $ as a function. Don't do that.";
823 | }
824 |
825 | };
826 | }
827 |
828 | // Taken from https://stackoverflow.com/questions/14743536/multiple-key-names-same-pair-value .
829 | function expand(obj) {
830 | var keys = Object.keys(obj);
831 | for(let cou = 0; cou < keys.length; cou++) {
832 | var key = keys[cou];
833 | var subkeys = key.split(/,\s?/);
834 | var target = obj[key];
835 | target.main_alias = subkeys[0];
836 | target.aliases = subkeys;
837 | delete obj[key];
838 | subkeys.forEach(key => {
839 | obj[key] = target;
840 | obj[key.replace("_", "")] = target;
841 | obj[key.replace(/(_\w)/g, m => m[1].toUpperCase())] = target;
842 | });
843 | }
844 | return obj;
845 | }
846 |
847 | module.exports = {built_ins, operators};
--------------------------------------------------------------------------------
/calc/help.js:
--------------------------------------------------------------------------------
1 | var help_menu = `
2 |
3 | CALC=
4 |
5 | Welcome to calc=, the stack language for chats! For a basic tutorial, type "calc= tut". If you already know stack based programming, use "calc= adv_tut".
6 |
7 | Demos:
8 | * Fibonacci: "calc= fib = {n -> 0 1 {x y -> y x y +} n iter drop} ; 0 9 .. $fib map"
9 | * Factorial: "calc= 1 5 .. 1 $* fold"
10 | `;
11 |
12 | var tut_pages = [`
13 |
14 | INTRODUCTION (0)
15 |
16 | calc= is a programming language for chats. Every program starts with "calc=" and then has a series of instructions to follow. calc= is a stack based (or concatenative) language, which means all of it's computations will be done using a stack. You can push things on top, then pop them off to use them. Try the program "calc= 5 1 -", then proceed to the next page of the tutorial. To access a page use "calc= number tut", where you replace "number" by the page number. The next page of this tutorial is at "calc= 1 tut".
17 | `,`
18 |
19 | FIRST EXAMPLE (1)
20 |
21 | As you can see, "calc= 5 1 -" gives back "calc= 4". This is because "5" pushed a "5" on top of the stack, then "1" pushed a "1". Finally "-" popped the top two elements from the stack, "5" and "1", and subtracted them to form "4". There are the four basic operators: "+", "-", "*", "/".
22 | `,`
23 |
24 | MULTIPLE OPERATIONS (2)
25 |
26 | The problem now is: how do you make more complicated calculations like "4 * 3 - 2". In calc=, there is no order of operations, because each symbol is read from left to right, you always know which goes first. In the case of "4 * 3 - 2", you would write "calc= 4 3 * 2 -". In the normal math example, "*" goes first so in calc= it will be towards the front of the program. In the normal math example, you last thing you do is subtract, so it will be at the very end of the calc= program. Now on to a more complex example: how would write "2 + (5 - 1) / 3"? Try to write it yourself, the answer is on the next page.
27 | `,`
28 |
29 | COMPLEX EXAMPLE (3)
30 |
31 | In calc=, "2 + (5 - 1) / 3" would be written as "calc= 5 1 - 3 / 2 +" (there are other ways, but this is the most straight forward one). You can see that parenthesis are not necesarry in calc= because the order is always explicit, "-" goes first, then "/", and finally "+".
32 | `,`
33 |
34 | CALLING FUNCTIONS (4)
35 |
36 | To call any function, you just need to provide it's arguments and write it's name. For example, the absolute value function, shortened to "abs", can be used like so: "calc= -2 abs" -> "calc=2". Use "calc= page" to find functions you need.
37 | `,`
38 |
39 | MAKING VARIABLES (5)
40 |
41 | Variables in calc= are not like normal mathematical variables. They are most similar to constants. For example: "calc= x = 3 ; x 4 +" defines a variable x as 3, then uses it. To define a variable, all you need to do is write the name, an equals sign (=), it's value, and a somecolon (;) to finish it. Here is a more complex example: "calc= x = 2 sqrt ; y = 6 2 + ; x 2 / y". x is set to the square root of 2, y is 6 + 2, and the result is x / 2 and y.
42 | `,`
43 |
44 | CUSTOM FUNCTIONS (6)
45 |
46 | You can make your own functions as you would make a variable. For example, the square function would be defined and possibly used like so: "calc= square = {x -> x x *} ; 4 square" -> "calc=16". Here, the function definition starts at the "{" and ends at the "}". The variable names before the "->" are the arguments, in that case, "x" is the only argument. What comes after the "->" is the function body. When the function, gets called, the arguments get defined and the body gets called.
47 | `,`
48 |
49 | LISTS (7)
50 |
51 | The next useful feature would be lists. Lists are somewhat similar to mathematical sets, except that elements inside it are ordered and may be repeated. The syntax for lists is like so: "calc= [3, 6, 1]", makes the list containing, in that order, 3, 6, and 1. Lists are the best way to manipulate multiple values at once in calc=. One of the ways to manipulate these values is to "map" over them. For example, to add 1 to all the elements in a list, you would map over it with the function that adds one. The function that adds one would be "calc= {x -> x 1 +}". To actually map over a list, use the function "map", possible like so: "calc= [3, 6, 1] {x -> x 1 +} map" giving "calc=[4, 7, 2]".
52 | `,`
53 |
54 | THANK YOU (8)
55 |
56 | That's the entire basic tutorial for now. If you want to help add to it, you can contribute at https://github.com/Camto/calc .
57 | `];
58 |
59 | var adv_tut_pages = [`
60 |
61 | INTRODUCTION (0)
62 |
63 | calc= is a fairly typical concatenative language, with it's biggest difference being that it's meant to be run on one line. Every program has to start with "calc=", for compatibility with chat bots.
64 |
65 | First up is numbers, calc= only has floating points, which are used to approximate integers. calc= numbers have the same syntax as any other language.
66 |
67 | To access different pages of the tutorial, use "calc= number adv_tut" with the page number, "calc= 1 adv_tut", for example.
68 | `,`
69 |
70 | BUILT-INS, FUNCTIONS, AND OPERATORS (1)
71 |
72 | When accessing these tutorial pages, you're using a built-in function, namely "adv_tut". You can use "calc= page" to go to the built-in index (which I recommend you check now), or "calc= $name page", where "name" is the name of a built-in or operator, for example "calc= $adv_tut page" or "calc= $+ page". By the way, almost every built-in has one or more aliases, which are alternate names you can use to refer to it, so you don't have to remember the main name if you're used to another one.
73 |
74 | As for defining your own functions, you can define an anonymous function with "{arguments -> body}", for example "calc= {w h -> w 2 * h 2 * +}" pushes the perimited function to the stack (The "+" and "*" are operators, found at "calc= "operator" page"). But because functions can do what they want with the stack, this can be rewritten as "calc= {2 * swap 2 * +}". It may be harder to read, but calc= isn't meant to be especially readable, it's meant to be quick to write.
75 | `,`
76 |
77 | VARIABLES (2)
78 |
79 | As part of the main program or function body (after the argument's "->"), you can have variable definitions. Variables are defined with "name = expression ; body", where expression is any calc= expression and body can be more variables or an expression. For example:
80 |
81 | "calc= pythagoras = {x = dup fst ; y = snd ; x 2 ^ y 2 ^ + sqrt} ; "pythagoras of [3, 4] is" [3, 4] pythagoras "pythagoras of [5, 12] is" [5, 12] pythagoras"
82 |
83 | (the lists and strings will be explained on the next page)
84 |
85 | Variables are mutable using the built-ins at "calc= "state" page" and references (explained at "calc= 5 adv_tut"), but this is not recommended, as there is almost always a better way to do it. Also, as implemented now, mutation works well but still has a few bugs.
86 | `,`
87 |
88 | LISTS AND STRINGS (3)
89 |
90 | Lists are the only composite data type in calc=, and have a syntax of "calc= [1, 2, "string"]". Strings are for the most part treated as lists of characters, and if a built-in that works with lists doesn't work with strings, then it will be fixed in a later calc= version.
91 |
92 | As with the rest of the language, lists can abuse of the stack for more consiceness, for example "calc= [1, 2, 3]" will give the same result as "calc= 1 2 3 [,,]". The edge case here is that "calc= [1]" will not be the same as "calc= 1 []" because "[]" refers to an empty list, not one to be filled with one element. Instead, use "calc= 1 [id]", because "id" is a built-in that does nothing.
93 | `,`
94 |
95 | FUNCTIONAL LIST MANIPULATION (4)
96 |
97 | Since calc= is an almost pure functional programming language, the list manipulation is done in a functional way, with "map", "filter", "fold", and more at "calc= "list" page". For more info on those three most important ones, visit their pages.
98 | `,`
99 |
100 | REFERENCES (5)
101 |
102 | You can push references of variables, arguments, built-ins, or operators to the stack with "$". This means you can do
103 |
104 | "calc= square = {2 ^} ; 1 5 .. $square map"
105 |
106 | instead of
107 |
108 | "calc= square = {2 ^} ; 1 5 .. {square} map"
109 |
110 | and
111 |
112 | "calc= 1 5 .. 1 $* fold"
113 |
114 | instead of
115 |
116 | "calc= 1 5 .. 1 {*} fold"
117 | `,`
118 |
119 | THANK YOU (6)
120 |
121 | That's the entire advanced tutorial for now. If you want to help add to it, you can contribute at https://github.com/Camto/calc .
122 | `];
123 |
124 | var find_page_tip = `To find the help page of a built-in or an operator, just run "calc= $name page", where "name" is the name of the built-in or the operator.`
125 |
126 | var page_index = `
127 |
128 | HELP PAGES
129 |
130 | This is the help page index!
131 |
132 | ${find_page_tip}
133 |
134 | The built-ins are sorted by these categories:
135 | * Help functions. "calc= "help" page"
136 | * Basic functions. "calc= "basic" page"
137 | * Flow control. "calc= "control" page"
138 | * Stack functions. "calc= "stack" page"
139 | * List functions. "calc= "list" page"
140 | * Math functions. "calc= "math" page"
141 | * Function functions. "calc= "function" page"
142 | * State functions. "calc= "state" page"
143 | * Operators. "calc= "operator" page"
144 | `;
145 |
146 | var page_categories = {
147 | help: `
148 |
149 | HELP FUNCTIONS
150 |
151 | ${find_page_tip}
152 |
153 | These are the functions that explain calc=:
154 | * page - Built-in/operator documentation.
155 | * tut - Basic tutorial.
156 | * adv_tut - Advanced tutorial.
157 | `,
158 | basic: `
159 |
160 | BASIC FUNCTIONS
161 |
162 | ${find_page_tip}
163 |
164 | These are the fundamental functions:
165 | * type - Get type.
166 | * true
167 | * false
168 | * num_to_str - Convert number to string.
169 | * str_to_num - Convert string to number.
170 | * eval - Evaluate calc= program.
171 | `,
172 | control: `
173 |
174 | FLOW CONTROL
175 |
176 | ${find_page_tip}
177 |
178 | There are the functions for controllin the program flow:
179 | * if - If/else statement.
180 | `,
181 | stack: `
182 |
183 | STACK FUNCTIONS
184 |
185 | ${find_page_tip}
186 |
187 | These are the functions that manipulate the stack:
188 | * dup - Duplicate.
189 | * swap
190 | * stack_reverse_n - Reverse top n items.
191 | * drop
192 | * drop_n - Drop n items.
193 | * rot - Rotate.
194 | * unrot - Rotate backward.
195 | * roll - Roll.
196 | * unroll - Roll backward.
197 | * nip - Nip under.
198 | * tuck - Tuck under.
199 | * over - Duplicate over.
200 | `,
201 | list: `
202 |
203 | LIST FUNCTIONS
204 |
205 | ${find_page_tip}
206 |
207 | These are the functions for list manipulation:
208 | * map - Map over list.
209 | * fold - Fold list to the left.
210 | * foldr - Fold list to the right.
211 | * filter - Filter list with predicate.
212 | * length - Length of.
213 | * head - First item.
214 | * snd - Second item.
215 | * last - Last item.
216 | * back_snd - Before last item.
217 | * nth - N-th item.
218 | * back_nth - N-th item from the end.
219 | * init - All but first item.
220 | * tail - All but last item.
221 | * body - All but first and last item.
222 | * reverse - Reverse list.
223 | * reverse_n - Reverse last n items of list.
224 | * pop_n - Remove last n items of list.
225 | * elem - Is item in list.
226 | * join - Join list into string.
227 | * split - Split string into list.
228 | * expl - Explode list items.
229 | * group - Group into list.
230 | * copy_group - Copy and group into list.
231 | * box - Box item into list.
232 | * copy_box - Copy and box item into list.
233 | * group_all - Group all items into list.
234 | * copy_group_all - Copy and group all items into list.
235 | * list_dup - Duplicate top of list.
236 | * list_swap - Swap top of list.
237 | * list_rot - Rotate top of list.
238 | * list_unrot - Rotate top of list backward.
239 | * list_roll - Roll top of list.
240 | * list_unroll - Roll top of list backward.
241 | * list_nip - Nip under list.
242 | * list_tuck - Tuck under list.
243 | * list_over - Duplicate over on list.
244 | `,
245 | "math": `
246 |
247 | MATH FUNCTIONS
248 |
249 | ${find_page_tip}
250 |
251 | These are the mathematical functions:
252 | * pi - The constant pi.
253 | * tau - The constant tau.
254 | * e - The constant e.
255 | * abs - Absolute value.
256 | * round - Round to the nearest integer.
257 | * ceil - Round upwards.
258 | * floor - Round downwards.
259 | * max - Biggest or longest.
260 | * min - Smallest or shortest.
261 | * sgn - Sign of number.
262 | * evn - Is number even.
263 | * odd - Is number odd.
264 | * rand - Generate random number.
265 | * cos - Cosine of angle in radians.
266 | * sin - Sine of angle in radians.
267 | * tan - Tangent of angle in radians.
268 | * sec - Secant of angle in radians.
269 | * csc - Cosecant of angle in radians.
270 | * cot - Cotangent of angle in radians.
271 | * sqrt - Square root.
272 | * cbrt - Cube root.
273 | * root - N-th root.
274 | * log - Logarithm.
275 | * ln - Natural logarithm.
276 | `,
277 | "function": `
278 |
279 | FUNCTION FUNCTIONS
280 |
281 | ${find_page_tip}
282 |
283 | These are the functions that manipulate other functions:
284 | * call - Call function or built-in.
285 | * iter - Iterate over.
286 | * id - Identity function.
287 | * comp - Compose functions.
288 | `,
289 | state: `
290 |
291 | STATE FUNCTIONS
292 |
293 | ${find_page_tip}
294 |
295 | These are functions that manipulate the program state:
296 | * set - Set variable.
297 | * inc - Increment variable.
298 | * dec - Decrement variable.
299 | `,
300 | operator: `
301 |
302 | OPERATORS
303 |
304 | ${find_page_tip}
305 |
306 | These are the calc= operators:
307 | * "+" - Addition or concatenation.
308 | * "-" - Subtraction or slicing.
309 | * "*" - Multiplication, list-like repitition, or cartiesian products.
310 | * "/" - Division.
311 | * "^" - Exponetiation.
312 | * "%" - Modulo.
313 | * ".." - To from range.
314 | * "&" - Logical and.
315 | * "|" - Logical or.
316 | * "!" - Logical not.
317 | * "=" - Are equals.
318 | * "!=" - Aren't equals.
319 | * "<" - Less than or shorter than.
320 | * ">" - More than or longer than.
321 | * "<=" - Less than, equal to, longer than, or same length.
322 | * ">=" - More than, equal to, shorter than, or same length.
323 | `
324 | };
325 |
326 | var built_in_warning = "!WARNING: This function is discouraged from being used, the only reason it is here is for the few cases in which it is necessary!";
327 |
328 | var help_pages = {
329 | help: aliases => `
330 |
331 | HELP MENU
332 |
333 | Usage: "calc= help"
334 |
335 | Aliases: ${aliases}.
336 |
337 | It shows the main calc= menu.
338 | `,
339 | page: aliases => `
340 |
341 | BUILT-IN/OPERATOR DOCUMENTATION
342 |
343 | Usage: "calc= page" or "calc= $command page", where "command" is the name of a built-in or an operator.
344 |
345 | Aliases: ${aliases}.
346 |
347 | Examples:
348 | * "calc= $+ page"
349 | * "calc= $page page"
350 |
351 | Without any arguments, it shows how to use the documentation. With a symbol or operator, it shows the help page of the built-in or operator.
352 | `,
353 | tut: aliases => `
354 |
355 | BASIC TUTORIAL
356 |
357 | Usage: "calc= tut" or "calc= n tut", where "n" is the tutorial page number.
358 |
359 | Aliases: ${aliases}.
360 |
361 | It shows the basic tutorial page.
362 | `,
363 | adv_tut: aliases => `
364 |
365 | ADVANCED TUTORIAL
366 |
367 | Usage: "calc= adv_tut" or "calc= n adv_tut", where "n" is the tutorial page number.
368 |
369 | Aliases: ${aliases}.
370 |
371 | It shows the advanced tutorial page.
372 | `,
373 | type: aliases => `
374 |
375 | GET TYPE
376 |
377 | Usage: "calc= value type", where "value" is any value.
378 |
379 | Aliases: ${aliases}.
380 |
381 | Examples:
382 | * "calc= 1 type" -> "calc=number"
383 | * "calc= {} type" -> "calc=function"
384 |
385 | Returns the type of any given value. These can be: number, string, list, function, symbol, or operator.
386 | `,
387 | "true": aliases => `
388 |
389 | TRUE
390 |
391 | Usage: "calc= true".
392 |
393 | Aliases: ${aliases}.
394 |
395 | Examples:
396 | * "calc= true" -> "calc=1"
397 |
398 | Returns the simplest truthy value, 1.
399 | `,
400 | "false": aliases => `
401 |
402 | FALSE
403 |
404 | Usage: "calc= false".
405 |
406 | Aliases: ${aliases}.
407 |
408 | Examples:
409 | * "calc= false" -> "calc=0"
410 |
411 | Returns the simplest falsy value, 0.
412 | `,
413 | num_to_str: aliases => `
414 |
415 | CONVERT NUMBER TO STRING
416 |
417 | Usage: "calc= number num_to_str", where "number" is any number.
418 |
419 | Aliases: ${aliases}.
420 |
421 | Examples:
422 | * "calc= 5 num_to_str" -> "calc=5"
423 | * "calc= 5 num_to_str type" -> "calc=string"
424 |
425 | It returns the number as a string.
426 | `,
427 | str_to_num: aliases => `
428 |
429 | CONVERT STRING TO NUMBER
430 |
431 | Usage: "calc= string str_to_num", where "string" is a string representing a number.
432 |
433 | Aliases: ${aliases}.
434 |
435 | Examples:
436 | * "calc= "5" str_to_num" -> "calc=5"
437 | * "calc= "5" str_to_num type" -> "calc=number"
438 |
439 | It returns the string as a number.
440 | `,
441 | eval: aliases => `
442 |
443 | EVALUATE CALC= PROGRAM
444 |
445 | ${built_in_warning}
446 |
447 | Usage: "calc= program eval", where "program" is a string representing a calc= program.
448 |
449 | Aliases: ${aliases}.
450 |
451 | Examples:
452 | * "calc= "calc= 1 2 + 6" eval" -> "calc=[3, 6]"
453 | * "calc= "calc= " 5 num_to_str " 4 +" + + eval" -> "calc=[9]"
454 | * "calc= "" {"calc= \"" swap "\" 'a+" + + eval fst} 3 iter" -> "calc=aaa"
455 | * "calc= "calc= \\"calc= 1\\"eval" eval" -> "calc=[[1]]"
456 |
457 | It returns the stack of the result of the program.
458 | `,
459 | "if": aliases => `
460 |
461 | IF/ELSE STATEMENT
462 |
463 | Usage: "calc= bool if_true if_false if", where "bool" is a truthy of falsy value, "if_true" is the branch for if the condition is true, and "if_false" is the alternate branch.
464 |
465 | Aliases: ${aliases}.
466 |
467 | Examples:
468 | * "calc= 3 true {1+} {1-} if" -> "calc=4"
469 | * "calc= 3 0 {1+} {1-} if" -> "calc=2"
470 | * "calc= "oigb" $5 $3 if" -> "calc=5"
471 | * "calc= false $5 $3 if" -> "calc=3"
472 |
473 | If the condition is true, it executes the first branch, if not, then it executes the other branch.
474 |
475 | For different types, there are different ways to test if it is truthy:
476 | * Numbers that are 0 are falsy others are truthy.
477 | * String and Lists are treated as a number of their length, emptiness being 0, or falsy.
478 | * Functions, symbols, and operators are all truthy.
479 | `,
480 | dup: aliases => `
481 |
482 | DUPLICATE
483 |
484 | Usage: "calc= a dup", where "a" is any value.
485 |
486 | Aliases: ${aliases}.
487 |
488 | Examples:
489 | * "calc= 5 dup" -> "calc=5 5"
490 | * "calc= "ble" "str" dup" -> "calc=ble str str"
491 |
492 | It duplicates the top value of the stack. You can use dup to use some value without discarding it.
493 | `,
494 | swap: aliases => `
495 |
496 | SWAP
497 |
498 | Usage: "calc= a b swap", where "a" and "b" can be any value.
499 |
500 | Aliases: ${aliases}.
501 |
502 | Examples:
503 | * "calc= 2 5 swap" -> "calc=5 2"
504 | * "calc= "gh" [1, 2, 3] swap" -> "calc=[1, 2, 3] gh"
505 |
506 | It swaps the top 2 values of the stack. This means you can use a value underneath another.
507 | `,
508 | stack_reverse_n: aliases => `
509 |
510 | REVERSE TOP N ITEMS
511 |
512 | ${built_in_warning}
513 |
514 | Usage: "calc= n ... m num stack_reversen", where "num" is the amount of items you want to reverse and "n ... m" are the items.
515 |
516 | Aliases: ${aliases}.
517 |
518 | Examples:
519 | * "calc= 'a 'd 'y 'f 4 stack_reversen" -> "calc=f y d a"
520 | * "calc= 10 6 .. expl 1 5 .. expl 10 stack_reversen" -> "calc= 5 4 3 2 1 6 7 8 9 10"
521 |
522 | It reverses the top num items of the stack.
523 | `,
524 | drop: aliases => `
525 |
526 | DROP
527 |
528 | Usage: "calc= a drop", where "a" is any value.
529 |
530 | Aliases: ${aliases}.
531 |
532 | Examples:
533 | * "calc= 1 2 3 drop" -> "calc=1 2"
534 | * "calc= 'a 'b [] drop" -> "calc=a b"
535 |
536 | It removes the top item of the stack.
537 | `,
538 | drop_n: aliases => `
539 |
540 | DROP N ITEMS
541 |
542 | ${built_in_warning}
543 |
544 | Usage: "calc= n ... m num dropn", where "num" is the amount of items you want to drop and "n ... m" are the items.
545 |
546 | Aliases: ${aliases}.
547 |
548 | Examples:
549 | * "calc= 'a 'b 'c 'd 2 dropn" -> "calc=a b"
550 | * "calc= 10 1 .. expl 5 dropn" -> "calc=10 9 8 7 6"
551 |
552 | It drops the top num items of the stack. It should be called with a known, fixed number or you could remove the wrong items, which would cause very strange bugs.
553 | `,
554 | rot: aliases => `
555 |
556 | ROTATE
557 |
558 | Usage: "calc= a b c rot", where "a", "b", and "c" can be any value.
559 |
560 | Aliases: ${aliases}.
561 |
562 | Examples:
563 | * "calc= 'a 'b 'c rot" -> "calc=c a b"
564 | * "calc= "as" [] 1 rot" -> "calc=1 as []"
565 |
566 | It rotates the top three items of the stack to the right. To do this with more items you would use roll, but it is not recommended.
567 | `,
568 | unrot: aliases => `
569 |
570 | ROTATE BACKWARD
571 |
572 | Usage: "calc= a b c unrot", where "a", "b", and "c" can be any value.
573 |
574 | Aliases: ${aliases}.
575 |
576 | Examples:
577 | * "calc= 'a 'b 'c unrot" -> "calc=b c a"
578 | * "calc= "as" [] 1 unrot" -> "calc=[] 1 as"
579 |
580 | It rotates the top three items of the stack to the left. To do this with more items you would use unroll, but it is not recommended.
581 | `,
582 | roll: aliases => `
583 |
584 | ROLL
585 |
586 | ${built_in_warning}
587 |
588 | Usage: "calc= n ... m num roll", where "num" is the amount of items you want to roll and "n ... m" are the items.
589 |
590 | Aliases: ${aliases}.
591 |
592 | Examples:
593 | * "calc= 'a 'b 'c 'd 'e 'f 4 roll" -> "calc=a b f c d e"
594 | * "calc= 1 5 .. {n -> 1 n .. expl n roll n group} map" -> "calc=[[1], [2, 1], [3, 1, 2], [4, 1, 2, 3], [5, 1, 2, 3, 4]]"
595 |
596 | It rotates the top num items of the stack to the left. If you want to roll 2 or 3 three items, please check out swap and rot.
597 | `,
598 | unroll: aliases => `
599 |
600 | ROLL BACKWARD
601 |
602 | ${built_in_warning}
603 |
604 | Usage: "calc= n ... m num unroll", where "num" is the amount of items you want to roll backward and "n ... m" are the items.
605 |
606 | Aliases: ${aliases}.
607 |
608 | Examples:
609 | * "calc= 'a 'b 'c 'd 'e 'f 4 unroll" -> "calc=a b d e f c"
610 | * "calc= 1 5 .. {n -> 1 n .. expl n unroll n group} map" -> "calc=[[1], [2, 1], [2, 3, 1], [2, 3, 4, 1], [2, 3, 4, 5, 1]]"
611 |
612 | It rotates the top num items of the stack to the right. If you want to roll backward 2 or 3 three items, please check out swap and unrot.
613 | `,
614 | nip: aliases => `
615 |
616 | NIP UNDER
617 |
618 | Usage: "calc= a b nip", where "a" and "b" can be any value.
619 |
620 | Aliases: ${aliases}.
621 |
622 | Examples:
623 | * "calc= 'a 'b 'c nip" -> "calc=a c"
624 | * "calc= 6 1 78 2 nip" -> "calc=6 1 2"
625 |
626 | It removes the item under the top one. Equivalent to "swap drop".
627 | `,
628 | tuck: aliases => `
629 |
630 | TUCK UNDER
631 |
632 | Usage: "calc= a b nip", where "a" and "b" can be any value.
633 |
634 | Aliases: ${aliases}.
635 |
636 | Examples:
637 | * "calc= 'a 'b 'c tuck" -> "calc=a c b c"
638 | * "calc= 1 [2] tuck" -> "calc=[2] 1 [2]"
639 |
640 | It puts the top item of the stack underneath the next. Equivalent to "dup rot" or "swap over".
641 | `,
642 | over: aliases => `
643 |
644 | DUPLICATE OVER
645 |
646 | Usage: "calc= a b over", where "a" and "b" can be any value.
647 |
648 | Aliases: ${aliases}.
649 |
650 | Examples:
651 | * "calc= 'a 'b over" -> "calc=a b a"
652 | * "calc= 4 98 2 over" -> "calc=4 98 2 98"
653 |
654 | It puts a duplicate of the second item from the top of the stack on top of the stack. Equivalent to "swap dup rot" or "swap tuck".
655 | `,
656 | map: aliases => `
657 |
658 | MAP OVER LIST
659 |
660 | Usage: "calc= list func map", where "list" is a list and "func" is any function.
661 |
662 | Aliases: ${aliases}.
663 |
664 | Examples:
665 | * "calc= 3 6 .. {1+} map" -> "calc=[4, 5, 6, 7]"
666 | * "calc= [true, false, true] $! map" -> "calc=[0, 1, 0]"
667 |
668 | It applies the function to each element in the list. The function should take one argument and return one value, or else bugs might ensue.
669 | `,
670 | fold: aliases => `
671 |
672 | FOLD LIST TO THE LEFT
673 |
674 | Usage: "calc= list starting reducer fold", where "list" is a list, "starting" is the starting value for the folding, and "reducer" is the function for folding the list.
675 |
676 | Aliases: ${aliases}.
677 |
678 | Examples:
679 | * "calc= 1 5 .. 1 $* fold" -> "calc=120"
680 | * "calc= ["foo", "bar", "baz"] "" {", " + +} fold" -> "calc=foo, bar, baz, "
681 |
682 | It applies the function to the last result of the function (the accumulator) to the next element of the list. The first accumulator is the "starting" argument.
683 |
684 | Example explanation: "calc= 1 5 .. 1 $* fold".
685 | * [1, 2, 3, 4, 5] The list.
686 | * 1 The starting accumulator.
687 | * $* The reducer.
688 |
689 | The argument on the left is the accumulator and the one on the right is the next element in the list.
690 | 1 * 1 -> 1
691 | 1 * 2 -> 2
692 | 2 * 3 -> 6
693 | 6 * 4 -> 24
694 | 24 * 5 -> 120
695 |
696 | Then 120 is returned.
697 | `,
698 | foldr: aliases => `
699 |
700 | FOLD LIST TO THE RIGHT
701 |
702 | Usage: "calc= list starting reducer foldr", where "list" is a list, "starting" is the starting value for the folding, and "reducer" is the function for folding the list.
703 |
704 | Aliases: ${aliases}.
705 |
706 | Examples:
707 | * "calc= 1 5 .. 1 $* foldr" -> "calc=120"
708 | * "calc= ["foo", "bar", "baz"] "" {", " + +} foldr" -> "calc=baz, bar, foo, "
709 |
710 | It applies the function to the last result of the function (the accumulator) to the next element of the list, starting from the end. The first accumulator is the "starting" argument.
711 |
712 | Example explanation: "calc= 1 5 .. 1 $* foldr".
713 | * [1, 2, 3, 4, 5] The list.
714 | * 1 The starting accumulator.
715 | * $* The reducer.
716 |
717 | The argument on the left is the accumulator and the one on the right is the next element in the list.
718 | 1 * 5 -> 5
719 | 5 * 4 -> 20
720 | 20 * 3 -> 60
721 | 60 * 2 -> 120
722 | 120 * 1 -> 120
723 |
724 | Then 120 is returned.
725 | `,
726 | filter: aliases => `
727 |
728 | FILTER LIST WITH PREDICATE
729 |
730 | Usage: "calc= list pred filter", where "list" is a list and "pred" is any predicate (function that returns a boolean).
731 |
732 | Aliases: ${aliases}.
733 |
734 | Examples:
735 | * "calc= -5 5 .. {2 >} filter" -> "calc=[3, 4, 5]"
736 | * "calc= [-3 3 .., 1 2 .., -5 -3 .., [0, 3], [5, 1]] {0 elem !} filter" -> "calc=[[1, 2], [-5, -4, -3], [5, 1]]"
737 | * "calc= ["", "as", [], [1], 0, 1, {}, {+}, $0] {} filter" -> "calc=[as, [1], 1, { -> }, { -> }, 0]"
738 |
739 | It calls the predicate on each element in the list, keeping only the elements that return truthy values.
740 | `,
741 | length: aliases => `
742 |
743 | LENGTH OF
744 |
745 | Usage: "calc= list_like length", where "list_like" is a list or a string (like a list of characters).
746 |
747 | Aliases: ${aliases}.
748 |
749 | Examples:
750 | * "calc= [0, 1, 2] length" -> "calc=3"
751 | * "calc= "dbfj" length" -> "calc=4"
752 |
753 | It returns the length of the list_like.
754 | `,
755 | head: aliases => `
756 |
757 | FIRST ITEM
758 |
759 | Usage: "calc= list head", where "list" is a list.
760 |
761 | Aliases: ${aliases}.
762 |
763 | Examples:
764 | * "calc= [6, 2, 7] head" -> "calc=6"
765 | * "calc= 6 3 .. head" -> "calc=6"
766 |
767 | It returns the first item of the list.
768 | `,
769 | snd: aliases => `
770 |
771 | SECOND ITEM
772 |
773 | Usage: "calc= list snd", where "list" is a list.
774 |
775 | Aliases: ${aliases}.
776 |
777 | Examples:
778 | * "calc= [6, 2, 7] snd" -> "calc=2"
779 | * "calc= 6 3 .. snd" -> "calc=5"
780 |
781 | It returns the second item of the list.
782 | `,
783 | last: aliases => `
784 |
785 | LAST ITEM
786 |
787 | Usage: "calc= list last", where "list" is a list.
788 |
789 | Aliases: ${aliases}.
790 |
791 | Examples:
792 | * "calc= [6, 2, 7] last" -> "calc=7"
793 | * "calc= 6 3 .. last" -> "calc=3"
794 |
795 | It returns the last item of the list.
796 | `,
797 | back_snd: aliases => `
798 |
799 | BEFORE LAST ITEM
800 |
801 | Usage: "calc= list back_snd", where "list" is a list.
802 |
803 | Aliases: ${aliases}.
804 |
805 | Examples:
806 | * "calc= [6, 2, 7] back_snd" -> "calc=2"
807 | * "calc= 6 3 .. back_snd" -> "calc=4"
808 |
809 | It returns the before last item of the list.
810 | `,
811 | nth: aliases => `
812 |
813 | N-TH ITEM
814 |
815 | Usage: "calc= list idx nth", where "idx" is an index into the list and "list" is a list.
816 |
817 | Aliases: ${aliases}.
818 |
819 | Examples:
820 | * "calc= [866, 346, 987, 43] 2 nth" -> "calc=987"
821 | * "calc= 3 8 .. 3 nth" -> "calc=6"
822 |
823 | It returns the n-th item of the list, where idx is that n. The list is 0 indexed, meaning the first item is at index 0.
824 | `,
825 | back_nth: aliases => `
826 |
827 | N-TH ITEM FROM THE END
828 |
829 | Usage: "calc= list idx back_nth", where "idx" is an index into the list and "list" is a list.
830 |
831 | Aliases: ${aliases}.
832 |
833 | Examples:
834 | * "calc= [866, 346, 987, 43] 2 back_nth" -> "calc=346"
835 | * "calc= 3 8 .. 3 back_nth" -> "calc=5"
836 |
837 | It returns the n-th item from the back of the list, where idx is that n. The list is 0 indexed, meaning the last item is at index 0.
838 | `,
839 | init: aliases => `
840 |
841 | ALL BUT FIRST ITEM
842 |
843 | Usage: "calc= list init", where "list" is a list.
844 |
845 | Aliases: ${aliases}.
846 |
847 | Examples:
848 | * "calc= [6, 2, 7] init" -> "calc=[6, 2]"
849 | * "calc= 6 3 .. init" -> "calc=[6, 5, 4]"
850 |
851 | It returns all but the first item of the list.
852 | `,
853 | tail: aliases => `
854 |
855 | ALL BUT LAST ITEM
856 |
857 | Usage: "calc= list tail", where "list" is a list.
858 |
859 | Aliases: ${aliases}.
860 |
861 | Examples:
862 | * "calc= [6, 2, 7] tail" -> "calc=[2, 7]"
863 | * "calc= 6 3 .. tail" -> "calc=[5, 4, 3]"
864 |
865 | It returns all but the last item of the list.
866 | `,
867 | body: aliases => `
868 |
869 | ALL BUT FIRST AND LAST ITEM
870 |
871 | Usage: "calc= list body", where "list" is a list.
872 |
873 | Aliases: ${aliases}.
874 |
875 | Examples:
876 | * "calc= [6, 2, 7] body" -> "calc=[2]"
877 | * "calc= 6 3 .. body" -> "calc=[5, 4]"
878 |
879 | It returns all but the first and last item of the list.
880 | `,
881 | reverse: aliases => `
882 |
883 | REVERSE LIST
884 |
885 | Usage: "calc= list reverse", where "list" is a list.
886 |
887 | Aliases: ${aliases}.
888 |
889 | Examples:
890 | * "calc= 4 9 .. reverse" -> "calc=[9, 8, 7, 6, 5, 4]"
891 | * "calc= [7, 34, $-, "as", [], {}] reverse" -> "calc=[{ -> }, [], as, -, 34, 7]"
892 |
893 | It reverses the list.
894 | `,
895 | reverse_n: aliases => `
896 |
897 | REVERSE LAST N ITEMS OF LIST
898 |
899 | Usage: "calc= list num reverse", where "list" is a list and "num" is an index into the list.
900 |
901 | Aliases: ${aliases}.
902 |
903 | Examples:
904 | * "calc= 1 6 .. 4 reverse_n" -> "calc=[1, 2, 6, 5, 4, 3]"
905 | * "calc= [7, 34, $-, "as", [], {}] 3 reverse_n" -> "calc=[7, 34, -, { -> }, [], as]"
906 |
907 | It reverses only the last num items of the list.
908 | `,
909 | pop_n: aliases => `
910 |
911 | REMOVE LAST N ITEMS OF LIST
912 |
913 | Usage: "calc= list num pop_n", where "list" is a list and "num" is an index into the list.
914 |
915 | Aliases: ${aliases}.
916 |
917 | Examples:
918 | * "calc= 1 6 .. 4 pop_n" -> "calc=[1, 2]"
919 | * "calc= [7, 34, $-, "as", [], {}] 3 pop_n" -> "calc=[7, 34, -]"
920 |
921 | It removes the last num items of the list.
922 | `,
923 | elem: aliases => `
924 |
925 | IS ITEM IN LIST
926 |
927 | Usage: "calc= list item elem", where "list" is the list and "item" is the item to test for.
928 |
929 | Aliases: ${aliases}.
930 |
931 | Examples:
932 | * "calc= [7, {}, 4, 23, 'a, $+, 4, []] 4 elem" -> "calc=1"
933 | * "calc= [7, {}, 23, 'a, $+, []] 4 elem" -> "calc=0"
934 | * "calc= [-3 3 .., 1 2 .., -5 -3 .., [0, 3], [5, 1]] {0 elem !} filter" -> "calc=[[1, 2], [-5, -4, -3], [5, 1]]"
935 |
936 | It returns true if the item is in the list, else it returns false.
937 | `,
938 | join: aliases => `
939 |
940 | JOIN LIST INTO STRING
941 |
942 | Usage: "calc= list joiner join", where "list" is a list of strings and "joiner" is the string to put in between each item.
943 |
944 | Aliases: ${aliases}.
945 |
946 | Examples:
947 | * "calc= ['a, 'b, 'c] ': join" -> "calc=a:b:c"
948 | * "calc= ["as", "fdg", "bb"] "" join" -> "calc=asfdgbb"
949 |
950 | It returns the list as a string with the joiner in between each string in the list.
951 | `,
952 | split: aliases => `
953 |
954 | SPLIT STRING INTO LIST
955 |
956 | Usage: "calc= string splitter split", where "string" is a string and "splitter" is a string used to split the other.
957 |
958 | Aliases: ${aliases}.
959 |
960 | Examples:
961 | * "calc= "1,2,3,4" "," split" -> "calc=[1, 2, 3, 4]"
962 | * "calc= "iiodddoisoisoiso" "" split" -> "calc=[i, i, o, d, d, d, o, i, s, o, i, s, o, i, s, o]"
963 |
964 | It returns the string split into a list where it matches the splitter.
965 | `,
966 | expl: aliases => `
967 |
968 | EXPLODE LIST ITEMS
969 |
970 | ${built_in_warning}
971 |
972 | Usage: "calc= list expl", where "list" is a list.
973 |
974 | Aliases: ${aliases}.
975 |
976 | Examples:
977 | * "calc= 1 3 .. expl" -> "calc=1 2 3"
978 | * "calc= [67, 2, 'a, 2] expl" -> "calc=67 2 a 2"
979 |
980 | Every item of the list gets pushed to the top. The last item pushed will be the last item in the list.
981 | `,
982 | group: aliases => `
983 |
984 | GROUP INTO LIST
985 |
986 | ${built_in_warning}
987 |
988 | Usage: "calc= n ... m num group", where "num" is the amount of items you want to group and "n ... m" are the items.
989 |
990 | Aliases: ${aliases}.
991 |
992 | Examples:
993 | * "calc= 56 1 8 'f $+ 4 group" -> "calc=56 [1, 8, f, +]"
994 | * "calc= 4 6 .. expl 3 group" -> "calc=[4, 5, 6]"
995 |
996 | It pops the top num items and puts them into a list, where the first item in the list was the last popped.
997 | `,
998 | copy_group: aliases => `
999 |
1000 | COPY AND GROUP INTO LIST
1001 |
1002 | ${built_in_warning}
1003 |
1004 | Usage: "calc= n ... m num copy_group", where "num" is the amount of items you want to copy and group and "n ... m" are the items.
1005 |
1006 | Aliases: ${aliases}.
1007 |
1008 | Examples:
1009 | * "calc= 56 1 8 'f $+ 4 copy_group" -> "calc=56 1 8 f + [1, 8, f, +]"
1010 | * "calc= 4 6 .. expl 3 copy_group" -> "calc=4 5 6 [4, 5, 6]"
1011 |
1012 | It peeks at the top num items and puts them into a list, where the first item in the list was the last peeked at.
1013 | `,
1014 | box: aliases => `
1015 |
1016 | BOX ITEM INTO LIST
1017 |
1018 | Usage: "calc= n box", where n is the item.
1019 |
1020 | Aliases: ${aliases}.
1021 |
1022 | Examples:
1023 | * "calc= 3 box" -> "calc=[3]"
1024 | * "calc= "abc" box" -> "calc=["abc"]"
1025 |
1026 | It puts the top item into a list on its own.
1027 | `,
1028 | copy_box: aliases => `
1029 |
1030 | COPY AND BOX ITEM INTO LIST
1031 |
1032 | Usage: "calc= n copy_box", where n is the item.
1033 |
1034 | Aliases: ${aliases}.
1035 |
1036 | Examples:
1037 | * "calc= 3 copy_box" -> "calc=3 [3]"
1038 | * "calc= "abc" copy_box" -> "calc="abc" ["abc"]"
1039 |
1040 | It copies then puts the top item into a list on its own.
1041 | `,
1042 | group_all: aliases => `
1043 |
1044 | GROUP ALL ITEMS INTO LIST
1045 |
1046 | ${built_in_warning}
1047 |
1048 | Usage: "calc= n ... m group_all", where "n ... m" is the entire stack.
1049 |
1050 | Aliases: ${aliases}.
1051 |
1052 | Examples:
1053 | * "calc= 67 235 7 246 9 group_all" -> "calc=[67, 235, 7, 246, 9]"
1054 | * "calc= $+ 987 'q 87 37 008 group_all" -> "calc=[+, 987, q, 87, 37, 8]"
1055 |
1056 | It groups all the items, removing them after, into a list. The items near the top of the stack are near the end of the list.
1057 | `,
1058 | copy_group_all: aliases => `
1059 |
1060 | COPY AND GROUP ALL ITEMS INTO LIST
1061 |
1062 | ${built_in_warning}
1063 |
1064 | Usage: "calc= n ... m copy_group_all", where "n ... m" is the entire stack.
1065 |
1066 | Aliases: ${aliases}.
1067 |
1068 | Examples:
1069 | * "calc= 67 235 7 246 9 copy_group_all" -> "calc=67 235 7 246 9 [67, 235, 7, 246, 9]"
1070 | * "calc= $+ 987 'q 87 37 008 copy_group_all" -> "+ 987 q 87 37 8 calc=[+, 987, q, 87, 37, 8]"
1071 |
1072 | It groups all the items, without removing them, into a list. The items near the top f the stack are near the end of the list.
1073 | `,
1074 | list_dup: aliases => `
1075 |
1076 | DUPLICATE TOP OF LIST
1077 |
1078 | Usage: "calc= list dup", where "list" is a list with at least 1 item.
1079 |
1080 | Aliases: ${aliases}.
1081 |
1082 | Examples:
1083 | * "calc= [5] list_dup" -> "calc=[5, 5]"
1084 | * "calc= ["ble", "str"] list_dup" -> "calc=[ble, str, str]"
1085 |
1086 | It duplicates the top value of the list.
1087 | `,
1088 | list_swap: aliases => `
1089 |
1090 | SWAP TOP OF LIST
1091 |
1092 | Usage: "calc= list swap", where "list" is a list with at least 2 items.
1093 |
1094 | Aliases: ${aliases}.
1095 |
1096 | Examples:
1097 | * "calc= [2, 5] list_swap" -> "calc=[5, 2]"
1098 | * "calc= ["gh", [1, 2, 3]] list_swap" -> "calc=[[1, 2, 3], gh]"
1099 |
1100 | It swaps the top 2 values of the list.
1101 | `,
1102 | list_rot: aliases => `
1103 |
1104 | ROTATE TOP OF list
1105 |
1106 | Usage: "calc= list list_rot", where "list" is a list with at least 3 items.
1107 |
1108 | Aliases: ${aliases}.
1109 |
1110 | Examples:
1111 | * "calc= ['a, 'b, 'c] list_rot" -> "calc=[c, a, b]"
1112 | * "calc= ["as", [], 1] list_rot" -> "calc=[1, as, []]"
1113 |
1114 | It rotates the top three items of the list to the right. To do this with more items you would use list_roll, but it is not recommended.
1115 | `,
1116 | list_unrot: aliases => `
1117 |
1118 | ROTATE TOP OF LIST BACKWARD
1119 |
1120 | Usage: "calc= list list_unrot", where "list" is a list with at least 3 items.
1121 |
1122 | Aliases: ${aliases}.
1123 |
1124 | Examples:
1125 | * "calc= ['a, 'b, 'c] list_unrot" -> "calc=[b, c, a]"
1126 | * "calc= ["as", [], 1] list_unrot" -> "calc=[[], 1, as]"
1127 |
1128 | It rotates the top three items of the list to the left. To do this with more items you would use list_unroll, but it is not recommended.
1129 | `,
1130 | list_roll: aliases => `
1131 |
1132 | ROLL TOP OF LIST
1133 |
1134 | ${built_in_warning}
1135 |
1136 | Usage: "calc= [n ... m] num roll", where "num" is the amount of items you want to roll and "[n ... m]" is a list with at least "num" items.
1137 |
1138 | Aliases: ${aliases}.
1139 |
1140 | Examples:
1141 | * "calc= ['a, 'b, 'c, 'd, 'e, 'f] 4 list_roll" -> "calc=[a, b, f, c, d, e]"
1142 | * "calc= 1 5 .. {n -> 1 n .. n list_roll} map" -> "calc=[[1], [2, 1], [3, 1, 2], [4, 1, 2, 3], [5, 1, 2, 3, 4]]"
1143 |
1144 | It rotates the top num items of the list to the left. If you want to roll 2 or 3 three items, please check out list_swap and list_rot.
1145 | `,
1146 | list_unroll: aliases => `
1147 |
1148 | ROLL TOP OF LIST BACKWARD
1149 |
1150 | ${built_in_warning}
1151 |
1152 | Usage: "calc= [n ... m] num unroll", where "num" is the amount of items you want to roll backward and "[n ... m]" is a list with at least "num" items.
1153 |
1154 | Aliases: ${aliases}.
1155 |
1156 | Examples:
1157 | * "calc= ['a, 'b, 'c, 'd, 'e, 'f] 4 list_unroll" -> "calc=[a, b, d, e, f, c]"
1158 | * "calc= 1 5 .. {n -> 1 n .. n list_unroll} map" -> "calc=[[1], [2, 1], [2, 3, 1], [2, 3, 4, 1], [2, 3, 4, 5, 1]]"
1159 |
1160 | It rotates the top num items of the list to the right. If you want to roll backward 2 or 3 three items, please check out list_swap and list_unrot.
1161 | `,
1162 | list_nip: aliases => `
1163 |
1164 | NIP UNDER LIST
1165 |
1166 | Usage: "calc= list list_nip", where "list" is a list with at least 2 items.
1167 |
1168 | Aliases: ${aliases}.
1169 |
1170 | Examples:
1171 | * "calc= ['a, 'b, 'c] list_nip" -> "calc=[a, c]"
1172 | * "calc= [6, 1, 78, 2] list_nip" -> "calc=[6, 1, 2]"
1173 |
1174 | It removes the item under the top one of the list. Equivalent to "list_swap list_drop".
1175 | `,
1176 | list_tuck: aliases => `
1177 |
1178 | TUCK UNDER LIST
1179 |
1180 | Usage: "calc= list list_tuck", where "list" is a list with at least 2 items.
1181 |
1182 | Aliases: ${aliases}.
1183 |
1184 | Examples:
1185 | * "calc= ['a, 'b, 'c] list_tuck" -> "calc=[a, c, b, c]"
1186 | * "calc= [1, [2]] list_tuck" -> "calc=[[2], 1, [2]]"
1187 |
1188 | It puts the top item of the list underneath the next. Equivalent to "list_dup list_rot" or "list_swap list_over".
1189 | `,
1190 | list_over: aliases => `
1191 |
1192 | DUPLICATE OVER ON LIST
1193 |
1194 | Usage: "calc= list list_over", where "list" is a list with at least 2 items.
1195 |
1196 | Aliases: ${aliases}.
1197 |
1198 | Examples:
1199 | * "calc= ['a, 'b] list_over" -> "calc=[a, b, a]"
1200 | * "calc= [4, 98, 2] list_over" -> "calc=[4, 98, 2, 98]"
1201 |
1202 | It puts a duplicate of the second item from the top of the list on top of the list. Equivalent to "list_swap list_dup list_rot" or "list_swap list_tuck".
1203 | `,
1204 | pi: aliases => `
1205 |
1206 | THE CONSTANT PI
1207 |
1208 | Usage: "calc= pi".
1209 |
1210 | Aliases: ${aliases}.
1211 |
1212 | Examples:
1213 | * "calc= pi 2 *" -> "calc=6.28318"
1214 | * "calc= circle_area = {dup * pi *} ; 1 5 .. $circle_area map" -> "calc=[3.14159, 12.56637, 28.27433, 50.26548, 78.53981]"
1215 |
1216 | It returns the mathematical constant pi. Same as "tau 2 /".
1217 | `,
1218 | tau: aliases => `
1219 |
1220 | THE CONSTANT TAU
1221 |
1222 | Usage: "calc= tau".
1223 |
1224 | Aliases: ${aliases}.
1225 |
1226 | Examples:
1227 | * "calc= tau 2 /" -> "calc=3.14159"
1228 | * "calc= circumference = {tau *} ; 1 5 .. $circumference map" -> "calc=[6.28318, 12.56637, 18.84955, 25.13274, 31.41592]"
1229 |
1230 | It returns the mathematical constant tau. Same as "pi 2 *".
1231 | `,
1232 | e: aliases => `
1233 |
1234 | THE CONSTANT E
1235 |
1236 | Usage: "calc= e".
1237 |
1238 | Aliases: ${aliases}.
1239 |
1240 | Examples:
1241 | * "calc= e ln" -> "calc=1"
1242 | * "calc= e 3 ^ ln" -> "calc=3"
1243 |
1244 | It returns the mathematical constant e, the base of the natural logarithm.
1245 | `,
1246 | abs: aliases => `
1247 |
1248 | ABSOLUTE VALUE
1249 |
1250 | Usage: "calc= num abs" where "num" is a number.
1251 |
1252 | Aliases: ${aliases}.
1253 |
1254 | Examples:
1255 | * "calc= -5 abs 0 abs 2 abs" -> "calc= 5 0 2"
1256 | * "calc= -5 5 .. $abs map" -> "calc= [5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5]"
1257 |
1258 | It returns the absolute value of num. For any number more than or equal to 0, it returns that number, else that number negated.
1259 | `,
1260 | round: aliases => `
1261 |
1262 | ROUND TO THE NEAREST INTEGER
1263 |
1264 | Usage: "calc= num round" where "num" is a number.
1265 |
1266 | Aliases: ${aliases}.
1267 |
1268 | Examples:
1269 | * "calc= -0.5 round" -> "calc=0"
1270 | * "calc= 0.5 round" -> "calc=1"
1271 | * "calc= 5 round" -> "calc=5"
1272 | * "calc= 7.25 round" -> "calc=7"
1273 | * "calc= 9.75 round" -> "calc=10"
1274 |
1275 | It returns num, rounded to the nearest integer. If the fractional part if .5, the number is rounded upwards.
1276 | `,
1277 | ceil: aliases => `
1278 |
1279 | ROUND UPWARDS
1280 |
1281 | Usage: "calc= num ceil" where "num" is a number.
1282 |
1283 | Aliases: ${aliases}.
1284 |
1285 | Examples:
1286 | * "calc= 4.5 ceil" -> "calc= 5"
1287 | * "calc= 4.2 ceil" -> "calc= 5"
1288 | * "calc= 6 ceil" -> "calc=6"
1289 | * "calc= -2.5 ceil" -> "calc= -2"
1290 |
1291 | It returns num rounded to the nearest integer greater or equal to it.
1292 | `,
1293 | floor: aliases => `
1294 |
1295 | ROUND DOWNWARDS
1296 |
1297 | Usage: "calc= num floor" where "num" is a number.
1298 |
1299 | Aliases: ${aliases}.
1300 |
1301 | Examples:
1302 | * "calc= 4.5 floor" -> "calc= 4"
1303 | * "calc= 4.7 floor" -> "calc= 4"
1304 | * "calc= 6 floor" -> "calc=6"
1305 | * "calc= -2.5 floor" -> "calc= -3"
1306 |
1307 | It returns num rounded to the nearest integer less than or equal to it.
1308 | `,
1309 | max: aliases => `
1310 |
1311 | BIGGEST OR LONGEST
1312 |
1313 | Usage: "calc= x y max" where "x" and "y" are numbers, lists, or strings (they must be the same type).
1314 |
1315 | Aliases: ${aliases}.
1316 |
1317 | Examples:
1318 | * "calc= 3 4 max" -> "calc=4"
1319 | * "calc= 6 -2 max" -> "calc=6"
1320 | * "calc= [1, 2, 3] [1] max" -> "calc=[1, 2, 3]"
1321 | * "calc= 'a "nice" max" -> "calc=nice"
1322 |
1323 | It returns the biggest or longest of two items.
1324 | `,
1325 | min: aliases => `
1326 |
1327 | SMALLEST OR SHORTEST
1328 |
1329 | Usage: "calc= x y min" where "x" and "y" are numbers, lists, or strings (they must be the same type).
1330 |
1331 | Aliases: ${aliases}.
1332 |
1333 | Examples:
1334 | * "calc= 3 4 min" -> "calc=3"
1335 | * "calc= 6 -2 min" -> "calc=-2"
1336 | * "calc= [1, 2, 3] [1] min" -> "calc=[1]"
1337 | * "calc= 'a "nice" min" -> "calc=a"
1338 |
1339 | It returns the smallest or shortest of two items.
1340 | `,
1341 | sgn: aliases => `
1342 |
1343 | SIGN OF NUMBER
1344 |
1345 | Usage: "calc= num sgn" where "num" is a number.
1346 |
1347 | Aliases: ${aliases}.
1348 |
1349 | Examples:
1350 | * "calc= 42 sgn" -> "calc=1"
1351 | * "calc= 0 sgn" -> "calc=0"
1352 | * "calc= -30 sgn" -> "calc=-1"
1353 | * "calc= -3 3 .. $sgn map" -> "calc=[-1, -1, -1, 0, 1, 1, 1]"
1354 |
1355 | It returns the sign of num, 1 for positive, -1 for negative, and 0 for none.
1356 | `,
1357 | evn: aliases => `
1358 |
1359 | IS NUMBER EVEN
1360 |
1361 | Usage: "calc= num evn" where "num" is a number.
1362 |
1363 | Aliases: ${aliases}.
1364 |
1365 | Example:
1366 | * "calc= 4 evn" -> "calc=1"
1367 | * "calc= -3 evn" -> "calc=0"
1368 | * "calc= -5 5 .. $evn map" -> "calc=[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]"
1369 |
1370 | It returns true (1) if the number is even, otherwise false (0).
1371 | `,
1372 | odd: aliases => `
1373 |
1374 | IS NUMBER ODD
1375 |
1376 | Usage: "calc= num odd" where "num" is a number.
1377 |
1378 | Aliases: ${aliases}.
1379 |
1380 | Example:
1381 | * "calc= 4 odd" -> "calc=1"
1382 | * "calc= -3 odd" -> "calc=0"
1383 | * "calc= -5 5 .. $odd map" -> "calc=[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]"
1384 |
1385 | It returns true (1) if the number is odd, otherwise false (0).
1386 | `,
1387 | rand: aliases => `
1388 |
1389 | GENERATE RANDOM NUMBER
1390 |
1391 | Usage: "calc= x y rand", where "x" and "y" are the boundaries of the random number.
1392 |
1393 | Aliases: ${aliases}.
1394 |
1395 | Examples:
1396 | * "calc= 3 4 rand" -> "calc=3.45051"
1397 | * "calc= 0 9 .. {drop 1 10 rand} map" -> "calc=[4.44581, 9.54312, 9.75568, 4.35409, 9.83876, 5.42639, 9.90467, 6.86817, 9.90735, 5.01449]"
1398 |
1399 | It returns are psuedo-random number between x and y (they don't have a specific order).
1400 | `,
1401 | cos: aliases => `
1402 |
1403 | COSINE OF ANGLE IN RADIANS
1404 |
1405 | Usage: "calc= angle cos". where "angle" is an angle in radians.
1406 |
1407 | Aliases: ${aliases}.
1408 |
1409 | Examples:
1410 | * "calc= 3 2 / pi * cos" -> "calc=0"
1411 | * "calc= 4 pi * cos" -> "calc=1"
1412 |
1413 | It returns the cosine of the given angle, which is in radians.
1414 | `,
1415 | sin: aliases => `
1416 |
1417 | SINE OF ANGLE IN RADIANS
1418 |
1419 | Usage: "calc= angle sin". where "angle" is an angle in radians.
1420 |
1421 | Aliases: ${aliases}.
1422 |
1423 | Examples:
1424 | * "calc= 3 2 / pi * sin" -> "calc=-1"
1425 | * "calc= 4 pi * sin" -> "calc=0"
1426 |
1427 | It returns the sine of the given angle, which is in radians.
1428 | `,
1429 | tan: aliases => `
1430 |
1431 | TANGENT OF ANGLE IN RADIANS
1432 |
1433 | Usage: "calc= angle tan". where "angle" is an angle in radians.
1434 |
1435 | Aliases: ${aliases}.
1436 |
1437 | Examples:
1438 | * "calc= pi 4 / tan" -> "calc=1"
1439 | * "calc= 3 pi * tan" -> "calc=0"
1440 |
1441 | It returns the tangent of the given angle, which is in radians.
1442 | `,
1443 | sec: aliases => `
1444 |
1445 | SECANT OF ANGLE IN RADIANS
1446 |
1447 | Usage: "calc= angle sec". where "angle" is an angle in radians.
1448 |
1449 | Aliases: ${aliases}.
1450 |
1451 | Examples:
1452 | * "calc= pi sec" -> "calc=-1"
1453 | * "calc= pi 4 / sec" -> "calc=1.41421"
1454 |
1455 | It returns the secant of the given angle, which is in radians.
1456 | `,
1457 | csc: aliases => `
1458 |
1459 | COSECANT OF ANGLE IN RADIANS
1460 |
1461 | Usage: "calc= angle csc". where "angle" is an angle in radians.
1462 |
1463 | Aliases: ${aliases}.
1464 |
1465 | Examples:
1466 | * "calc= pi 2 / csc" -> "calc=1"
1467 | * "calc= pi 4 / csc" -> "calc=1.41421"
1468 |
1469 | It returns the cosecant of the given angle, which is in radians.
1470 | `,
1471 | cot: aliases => `
1472 |
1473 | COTANGENT OF ANGLE IN RADIANS
1474 |
1475 | Usage: "calc= angle cot". where "angle" is an angle in radians.
1476 |
1477 | Aliases: ${aliases}.
1478 |
1479 | Examples:
1480 | * "calc= pi 4 / cot" -> "calc=1"
1481 | * "calc= pi 2 / cot" -> "calc=0"
1482 |
1483 | It returns the cotangent of the given angle, which is in radians.
1484 | `,
1485 | sqrt: aliases => `
1486 |
1487 | SQUARE ROOT
1488 |
1489 | Usage: "calc= num sqrt", where "num" is any number.
1490 |
1491 | Aliases: ${aliases}.
1492 |
1493 | Examples:
1494 | * "calc= 2 sqrt" -> "calc=1.41421"
1495 | * "calc= 9 sqrt" -> "calc=3"
1496 |
1497 | It returns the square root of num.
1498 | `,
1499 | cbrt: aliases => `
1500 |
1501 | CUBE ROOT
1502 |
1503 | Usage: "calc= num cbrt", where "num" is any number.
1504 |
1505 | Aliases: ${aliases}.
1506 |
1507 | Examples:
1508 | * "calc= 3 cbrt" -> "calc=1.44224"
1509 | * "calc= 64 cbrt" -> "calc=4"
1510 |
1511 | It returns the cube root of num.
1512 | `,
1513 | root: aliases => `
1514 |
1515 | N-TH ROOT
1516 |
1517 | Usage: "calc= num exp root", where "num" is any number and "exp" is an exponent.
1518 |
1519 | Aliases: ${aliases}.
1520 |
1521 | Examples:
1522 | "calc= 16 4 root" -> "calc=2"
1523 | "calc= 6 4 root" -> "calc=1.56508"
1524 |
1525 | It returns the exp-th root of num.
1526 | `,
1527 | log: aliases => `
1528 |
1529 | LOGARITHM
1530 |
1531 | Usage: "calc= num base log", where "num" is any number and "base" is a base.
1532 |
1533 | Aliases: ${aliases}.
1534 |
1535 | Examples:
1536 | * "calc= 1024 2 log" -> "calc=10"
1537 | * "calc= 27 3 log" -> "calc=3"
1538 |
1539 | It returns the logarithm of num to base.
1540 | `,
1541 | ln: aliases => `
1542 |
1543 | NATURAL LOGARITHM
1544 |
1545 | Usage: "calc= num ln" where "num" is any number.
1546 |
1547 | Aliases: ${aliases}.
1548 |
1549 | Examples:
1550 | * "calc= 3 ln" -> "calc=1.09861"
1551 | * "calc= e ln" -> "calc=1"
1552 |
1553 | It returns the logarithm of num to base e.
1554 | `,
1555 | call: aliases => `
1556 |
1557 | CALL FUNCTION OR BUILT-IN
1558 |
1559 | Usage: "calc= args callable call", where "callable" is a function, built-in reference, or other reference and "args" are the arguments to the callable.
1560 |
1561 | Aliases: ${aliases}.
1562 |
1563 | Examples:
1564 | * "calc= 1 {1+} call" -> "calc=2"
1565 | * "calc= $id dup call" -> "calc=id"
1566 | * "calc= func = {1+} ; 1 $func call" -> "calc=2"
1567 | * "calc= $3 call" -> "calc=3"
1568 |
1569 | It returns the result of the callable.
1570 | `,
1571 | iter: aliases => `
1572 |
1573 | ITERATE OVER
1574 |
1575 | Usage: "calc= initial_state iterator n iter", where "initial_state" are the first arguments to the iterating function, "iterator" is a function to iterate with, and "n" is how many iterations to run.
1576 |
1577 | Aliases: ${aliases}.
1578 |
1579 | Examples:
1580 | * "calc= 0 1 {x y -> y x y +} 6 iter" -> "calc=8 13"
1581 | * "calc= $'a 7 iter" -> "calc=a a a a a a a"
1582 |
1583 | It runs the iterator n times, feeding the output of the function to it's input, starting with the initial state. It returns the final result of the iterator.
1584 | `,
1585 | id: aliases => `
1586 |
1587 | IDENTITY FUNCTION
1588 |
1589 | Usage: "calc= id".
1590 |
1591 | Aliases: ${aliases}.
1592 |
1593 | Example:
1594 | "calc= 3 'a id" -> "calc=3 a"
1595 |
1596 | It does nothing.
1597 | `,
1598 | comp: aliases => `
1599 |
1600 | COMPOSE FUNCTIONS
1601 |
1602 | Usage: "calc= f g comp", where "f" and "g" are functions.
1603 |
1604 | Aliases: ${aliases}.
1605 |
1606 | Examples:
1607 | "calc= $3 {1+} comp call" -> "calc=4"
1608 | "calc= func = {1-} $sqrt comp ; 5 func" -> "calc=2"
1609 |
1610 | It returns the composition of the functions. The resulting function, when run, just executes f, then g. It would be equivalent to {f g}.
1611 | `,
1612 | set: aliases => `
1613 |
1614 | SET VARIABLE
1615 |
1616 | ${built_in_warning}
1617 |
1618 | Usage: "calc= variable value set", where "variable" is a variable reference and "value" is the new value for the variable.
1619 |
1620 | Aliases: ${aliases}.
1621 |
1622 | Examples:
1623 | * "calc= x = 3 ; x $x 4 set x" -> "calc=3 4"
1624 | * "calc= var = "thing" ; $var 1 5 .. set var" -> "calc=[1, 2, 3, 4, 5]"
1625 |
1626 | Sets the variable to the new value. Returns nothing.
1627 | `,
1628 | inc: aliases => `
1629 |
1630 | INCREMENT VARIABLE
1631 |
1632 | ${built_in_warning}
1633 |
1634 | Usage: "calc= variable inc", where "variable" is a variable reference.
1635 |
1636 | Aliases: ${aliases}.
1637 |
1638 | Examples:
1639 | * "calc= x = 4 ; x $x inc x" -> "calc=4 5"
1640 | * "calc= var = 89 ; $var inc var" -> "calc=90"
1641 |
1642 | It increments the variable. Returns nothing.
1643 | `,
1644 | dec: aliases => `
1645 |
1646 | DECREMENT VARIABLE
1647 |
1648 | ${built_in_warning}
1649 |
1650 | Usage: "calc= variable dec", where "variable" is a variable reference.
1651 |
1652 | Aliases: ${aliases}.
1653 |
1654 | Examples:
1655 | * "calc= x = 4 ; x $x dec x" -> "calc=4 3"
1656 | * "calc= var = 89 ; $var dec var" -> "calc=88"
1657 |
1658 | It decrements the variable. Returns nothing.
1659 | `
1660 | };
1661 |
1662 | op_help_pages = {
1663 | "+": `
1664 |
1665 | ADDITION OR CONCATENATION
1666 |
1667 | Usage: "calc= x y +", where "x" and "y" are either both numbers, strings, or lists, or one of them is the list and another is an item to be appended.
1668 |
1669 | Examples:
1670 | * (both numbers) "calc= 3 5 +" -> "calc=8"
1671 | * (both strings) "calc= "abc" "def" +" -> "calc=abcdef"
1672 | * (both strings) "calc= "asd" 'f +" -> "calc=asdf"
1673 | * (both lists) "calc= 1 3 .. 4 6 .. +" -> "calc=[1, 2, 3, 4, 5, 6]"
1674 | * (x is a list, y is an item) "calc= 1 3 .. 4 +" -> "calc=[1, 2, 3, 4]"
1675 | * (x is an item, y is a list) "calc= 'a 'e 'h .. +" -> "calc=[a, e, f, g, h]"
1676 |
1677 | If x and y are numbers, they are added. If they are strings or lists, they are concatenated. If one is a list and the other is an item, the item is appended to the list, to the beginning if it is to the left, to the end if it is to the right.
1678 |
1679 | Here is a visual way to think about it:
1680 | "calc= 1 [2, 3, 4] +"
1681 | x = 1, y = [2, 3, 4]
1682 | result = [1, 2, 3, 4]
1683 |
1684 | "calc= [2, 3, 4] 1 +"
1685 | x = [2, 3, 4], y = 1
1686 | result = [2, 3, 4, 1]
1687 | `,
1688 | "-": `
1689 |
1690 | SUBTRACTION OR SLICING
1691 |
1692 | Usage: "x y -", where "x" and "y" are either both numbers, or "x" is a list-like (list or string) and "y" is a number.
1693 |
1694 | Examples:
1695 | * (both numbers) "calc= 3 1 -" -> "calc=-2"
1696 | * (x is a list, y is a number) "calc= 'a 'z .. -6 -" -> "calc=[g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]"
1697 | * (x is a string, y is a number) "calc= "abcdef" 3 -" -> "calc=abc"
1698 |
1699 | If x and y are numbers, they are subtracted. If x is a list-like and y is a positive number, then y items or characters are removed from the end of x. If x is a list-like and y is a negative number, then y items or characters are removed from the beginning of x.
1700 | `,
1701 | "*": `
1702 |
1703 | MULTIPLICATION, LIST-LIKE REPETITION, OR CARTESIAN PRODUCTS
1704 |
1705 | Usage: "x y *", where "x" is either a number or a list-like (list or string) and "y" is either a number or a list-like (list or string).
1706 |
1707 | Examples:
1708 | * (both numbers) "calc= 4 5 *" -> "calc=20"
1709 | * (x is a list-like, y is a number) "calc= "abc" 3 *" -> "calc=abcabcabc"
1710 | * (both are list-likes) "calc= "def" 1 3 .. *" -> "calc=[[d, 1], [d, 2], [d, 3], [e, 1], [e, 2], [e, 3], [f, 1], [f, 2], [f, 3]]"
1711 | * (both strings) "calc= "abc" dup *" -> "calc=[aa, ab, ac, ba, bb, bc, ca, cb, cc]"
1712 |
1713 | If x and y are numbers, they are multiplied. If one is a list-like and the other is a number, the list-like is replicated that many times. If both are list-likes, their cartesian product is given, with pairs as lists of 2 elements. If both are strings, the cartesian product will use strings as pairs.
1714 | `,
1715 | "/": `
1716 |
1717 | DIVISION
1718 |
1719 | Usage: "calc= x y /", where "x" and "y" are both numbers.
1720 |
1721 | Examples:
1722 | * "calc= 6 3 /" -> "calc=2"
1723 | * "calc= 1 3 /" -> "calc=0.33333"
1724 |
1725 | It returns x divided by y.
1726 | `,
1727 | "^": `
1728 |
1729 | EXPONENTIATION
1730 |
1731 | Usage: "calc= x y ^", where "x" and "y" are both numbers.
1732 |
1733 | Examples:
1734 | * "calc= 3 2 ^" -> "calc=9"
1735 | * "calc= 10 -5 ^" -> "calc=0.00001"
1736 |
1737 | It returns x to the power of y.
1738 | `,
1739 | "%": `
1740 |
1741 | MODULO
1742 |
1743 | Usage: "calc= x y %", where "x" and "y" are both numbers.
1744 |
1745 | Examples:
1746 | * "calc= 5 3 %" -> "calc=2"
1747 | * "calc= -3 2 %" -> "calc=-1"
1748 |
1749 | It returns x modulo y, being the remainder of x divided by y.
1750 | `,
1751 | "..": `
1752 |
1753 | TO FROM RANGE
1754 |
1755 | Usage: "calc= from to ..", where "from" and "to" are either both numbers or characters (strings of length 1).
1756 |
1757 | Examples:
1758 | * (both numbers) "calc= -3 3 .." -> "calc=[-3, -2, -1, 0, 1, 2, 3]"
1759 | * (both numbers) "calc= 3 -3 .." -> "calc=[3, 2, 1, 0, -1, -2, -3]"
1760 | * (both characters) "calc= 'a 'f .." -> "calc=[a, b, c, d, e, f]"
1761 |
1762 | It returns a list starting from "from" and ending with "to", with an element in between for the distance of both. Charcters are treated as numbers in the ASCII table.
1763 | `,
1764 | "&": `
1765 |
1766 | LOGICAL AND
1767 |
1768 | Usage: "calc= x y &", where "x" and "y" are booleans (numbers).
1769 |
1770 | Examples:
1771 | * "calc= false 2 &" -> "calc=0"
1772 |
1773 | It returns true (1) when both values are truthy (non-0).
1774 | `,
1775 | "|": `
1776 |
1777 | LOGICAL OR
1778 |
1779 | Usage: "calc= x y |", where "x" and "y" are booleans (numbers).
1780 |
1781 | Examples:
1782 | * "calc= false 2 |" -> "calc=1"
1783 |
1784 | It returns true (1) when either value is truthy (non-0).
1785 | `,
1786 | "!": `
1787 |
1788 | LOGICAL NOT
1789 |
1790 | Usage: "calc= x !", where "x" is a boolean (number).
1791 |
1792 | Examples:
1793 | * "calc= false !" -> "calc=1"
1794 |
1795 | It returns true (1) when x is false (0), otherwise it returns false (0).
1796 | `,
1797 | "=": `
1798 |
1799 | ARE EQUALS
1800 |
1801 | Usage: "calc= x y =", where "x" and "y" are anything.
1802 |
1803 | Examples:
1804 | * "calc= 1 1 =" -> "calc=1"
1805 | * "calc= 1 2 =" -> "calc=0"
1806 | * "calc= "abc" "abc" =" -> "calc=1"
1807 | * "calc= "abc" "abd" =" -> "calc=0"
1808 | * "calc= 1 3 .. dup =" -> "calc=1"
1809 | * "calc= 1 3 .. 1 4 .. =" -> "calc=0"
1810 | * "calc= {} dup =" -> "calc=0"
1811 | * "calc= $a dup =" -> "calc=0"
1812 | * "calc= $+ dup =" -> "calc=0"
1813 |
1814 | If x and y are both numbers or strings, it returns true (1) if their values are the same, otherwise false (0). If they are both lists, it returns true (1) if they're the same length and all their values are the same, otherwise false (0). With every other comparison, it returns false (0).
1815 | `,
1816 | "!=": `
1817 | AREN'T EQUALS
1818 |
1819 | Usage: "calc= x y =", where "x" and "y" are anything.
1820 |
1821 | Examples:
1822 | * "calc= 1 1 !=" -> "calc=0"
1823 | * "calc= 1 2 !=" -> "calc=1"
1824 | * "calc= "abc" "abc" !=" -> "calc=0"
1825 | * "calc= "abc" "abd" !=" -> "calc=1"
1826 | * "calc= 1 3 .. dup !=" -> "calc=0"
1827 | * "calc= 1 3 .. 1 4 .. !=" -> "calc=1"
1828 | * "calc= {} dup !=" -> "calc=1"
1829 | * "calc= $a dup !=" -> "calc=1"
1830 | * "calc= $+ dup !=" -> "calc=1"
1831 |
1832 | It returns true (1) if "calc= x y =" would return false (0), otherwise it returns false (0).
1833 | `,
1834 | "<": `
1835 |
1836 | LESS THAN OR SHORTER THAN
1837 |
1838 | Usage: "calc= x y <", where "x" and "y" are both numbers or list-likes (list or string).
1839 |
1840 | Examples:
1841 | * "calc= 1 2 <" -> "calc=1"
1842 | * "calc= 4 4 <" -> "calc=0"
1843 | * "calc= [8, 2] [1, 2, 3] <" -> "calc=1"
1844 | * "calc= [8, 2, 9] "s" <" -> "calc=0"
1845 | * "calc= "das" "sfg" <" -> "calc=0"
1846 |
1847 | If x and y are numbers, it returns true if x is less than y, otherwise it returns false. If x and y are list-likes, it returns true if x is shorter than y, otherwise it returns false.
1848 | `,
1849 | ">": `
1850 |
1851 | MORE THAN OR LONGER THAN
1852 |
1853 | Usage: "calc= x y >", where "x" and "y" are both numbers or list-likes (list or string).
1854 |
1855 | Examples:
1856 | * "calc= 1 2 >" -> "calc=0"
1857 | * "calc= 4 4 >" -> "calc=0"
1858 | * "calc= [8, 2] [1, 2, 3] >" -> "calc=0"
1859 | * "calc= [8, 2, 9] "s" >" -> "calc=1"
1860 | * "calc= "das" "sfg" >" -> "calc=0"
1861 |
1862 | If x and y are numbers, it returns true if x is more than y, otherwise it returns false. If x and y are list-likes, it returns true if x is longer than y, otherwise it returns false.
1863 | `,
1864 | "<=": `
1865 |
1866 | LESS THAN, EQUAL TO, SHORTER THAN, OR SAME LENGTH
1867 |
1868 | Usage: "calc= x y <=", where "x" and "y" are both numbers or list-likes (list or string).
1869 |
1870 | Examples:
1871 | * "calc= 1 2 <=" -> "calc=1"
1872 | * "calc= 4 4 <=" -> "calc=1"
1873 | * "calc= [8, 2] [1, 2, 3] <=" -> "calc=1"
1874 | * "calc= [8, 2, 9] "s" <=" -> "calc=0"
1875 | * "calc= "das" "sfg" <=" -> "calc=1"
1876 |
1877 | If x and y are numbers, it returns true if x is less than or equal to y, otherwise it returns false. If x and y are list-likes, it returns true if x is shorter than or the same length as y, otherwise it returns false.
1878 | `,
1879 | ">=": `
1880 |
1881 | MORE THAN, EQUAL TO, LONGER THAN, OR SAME LENGTH
1882 |
1883 | Usage: "calc= x y >=", where "x" and "y" are both numbers or list-likes (list or string).
1884 |
1885 | Examples:
1886 | * "calc= 1 2 >=" -> "calc=0"
1887 | * "calc= 4 4 >=" -> "calc=1"
1888 | * "calc= [8, 2] [1, 2, 3] >=" -> "calc=0"
1889 | * "calc= [8, 2, 9] "s" >=" -> "calc=1"
1890 | * "calc= "das" "sfg" >=" -> "calc=1"
1891 |
1892 | If x and y are numbers, it returns true if x is more than or equal to y, otherwise it returns false. If x and y are list-likes, it returns true if x is longer than or the same length as y, otherwise it returns false.
1893 | `,
1894 | $: "Tried to get documentation of $ as a function. Don't do that."
1895 | };
1896 |
1897 | module.exports = {help_menu, tut_pages, adv_tut_pages, page_index, page_categories, help_pages, op_help_pages};
--------------------------------------------------------------------------------