From ebe07b02c856b11f3ed575c4a01c80deec4f22f1 Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Fri, 25 Sep 2020 19:42:35 +0100 Subject: [PATCH 01/61] Get list unpacking working --- c/compiler.c | 41 +++++++++++++++++++++++++++++++---------- c/debug.c | 2 ++ c/opcodes.h | 1 + c/vm.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/c/compiler.c b/c/compiler.c index 9e733107..d188dd36 100644 --- a/c/compiler.c +++ b/c/compiler.c @@ -1397,19 +1397,40 @@ static void funDeclaration(Compiler *compiler) { } static void varDeclaration(Compiler *compiler, bool constant) { - do { - uint8_t global = parseVariable(compiler, "Expect variable name.", constant); + if (match(compiler, TOKEN_LEFT_BRACKET)) { + uint8_t variables[255]; + int varCount = 0; - if (match(compiler, TOKEN_EQUAL) || constant) { - // Compile the initializer. - expression(compiler); - } else { - // Default to nil. - emitByte(compiler, OP_NIL); + do { + variables[varCount] = parseVariable(compiler, "Expect variable name.", constant); + varCount++; + } while (match(compiler, TOKEN_COMMA)); + + consume(compiler, TOKEN_RIGHT_BRACKET, "Expect ']' after list destructure."); + consume(compiler, TOKEN_EQUAL, "Expect '=' after list destructure."); + + expression(compiler); + + emitBytes(compiler, OP_UNPACK_LIST, varCount); + + for (int i = 0; i < varCount; ++i) { + defineVariable(compiler, variables[i], constant); } + } else { + do { + uint8_t global = parseVariable(compiler, "Expect variable name.", constant); - defineVariable(compiler, global, constant); - } while (match(compiler, TOKEN_COMMA)); + if (match(compiler, TOKEN_EQUAL) || constant) { + // Compile the initializer. + expression(compiler); + } else { + // Default to nil. + emitByte(compiler, OP_NIL); + } + + defineVariable(compiler, global, constant); + } while (match(compiler, TOKEN_COMMA)); + } consume(compiler, TOKEN_SEMICOLON, "Expect ';' after variable declaration."); } diff --git a/c/debug.c b/c/debug.c index aa778142..ecdda8f0 100644 --- a/c/debug.c +++ b/c/debug.c @@ -186,6 +186,8 @@ int disassembleInstruction(Chunk *chunk, int offset) { return simpleInstruction("OP_NEW_LIST", offset); case OP_ADD_LIST: return simpleInstruction("OP_ADD_LIST", offset); + case OP_UNPACK_LIST: + return byteInstruction("OP_UNPACK_LIST", chunk, offset); case OP_SUBSCRIPT: return simpleInstruction("OP_SUBSCRIPT", offset); case OP_SUBSCRIPT_ASSIGN: diff --git a/c/opcodes.h b/c/opcodes.h index 4e9d1131..fb8ad384 100644 --- a/c/opcodes.h +++ b/c/opcodes.h @@ -4,6 +4,7 @@ OPCODE(TRUE) OPCODE(FALSE) OPCODE(NEW_LIST) OPCODE(ADD_LIST) +OPCODE(UNPACK_LIST) OPCODE(NEW_DICT) OPCODE(ADD_DICT) OPCODE(SUBSCRIPT) diff --git a/c/vm.c b/c/vm.c index 7d207a2f..4662a3b5 100644 --- a/c/vm.c +++ b/c/vm.c @@ -1194,6 +1194,36 @@ static InterpretResult run(VM *vm) { DISPATCH(); } + CASE_CODE(UNPACK_LIST): { + int varCount = READ_BYTE(); + + if (!IS_LIST(peek(vm, 0))) { + frame->ip = ip; + runtimeError(vm, "Attempting to unpack a value which is not a list."); + return INTERPRET_RUNTIME_ERROR; + } + + ObjList *list = AS_LIST(pop(vm)); + + if (varCount != list->values.count) { + frame->ip = ip; + + if (varCount < list->values.count) { + runtimeError(vm, "Too many values to unpack"); + } else { + runtimeError(vm, "Not enough values to unpack"); + } + + return INTERPRET_RUNTIME_ERROR; + } + + for (int i = list->values.count; i >= 0; --i) { + push(vm, list->values.values[i]); + } + + DISPATCH(); + } + CASE_CODE(NEW_DICT): { ObjDict *dict = initDict(vm); push(vm, OBJ_VAL(dict)); From 975fe6643832f170f022c268b8f29c0290a8c5ac Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Sat, 26 Sep 2020 22:49:23 +0100 Subject: [PATCH 02/61] Update documentation URL in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad41d41e..2bf7b113 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ built upon the [craftinginterpreters tutorial](http://www.craftinginterpreters.c Dictu means `simplistic` in Latin. ### Dictu documentation -Documentation for Dictu can be found [here](https://jason2605.github.io/Dictu/) +Documentation for Dictu can be found [here](https://dictu-lang.com/) ## Running Dictu ```bash From 4f8c46bb8ce200ffae5c3a38fc448a2f5d147481 Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Mon, 28 Sep 2020 20:38:24 +0100 Subject: [PATCH 03/61] Add tests and documentation --- docs/docs/variables.md | 29 +++++++++++++++++++++++++++++ tests/variables/import.du | 1 + tests/variables/list-unpacking.du | 29 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 tests/variables/list-unpacking.du diff --git a/docs/docs/variables.md b/docs/docs/variables.md index 5097f922..05ed5856 100644 --- a/docs/docs/variables.md +++ b/docs/docs/variables.md @@ -85,6 +85,35 @@ print(x); // 10 const y = 10, z = 20; // Both y and z are constants ``` +### List unpacking + +List unpacking is a feature in which you can define multiple variables at a given time from values within a list. +To unpack the amount of variables being defined **must** match the amount of values within the list otherwise a runtime error will occur. +```js +// Fine +var [a, b, c] = [1, 2, 3]; +print(a); // 1 +print(b); // 2 +print(c); // 3 + +// Fine +const [x, y, z] = [1, 2, 3]; +print(x); // 1 +print(y); // 2 +print(z); // 3 + +// Fine +var myList = [1, 2, 3]; +var [val1, val2, val3] = myList; +print(val1); // 1 +print(val2); // 2 +print(val3); // 3 + +// Error! +var [d] = [1, 2]; +var [e, f] = [1]; +``` + ## Casting ### value.toString() diff --git a/tests/variables/import.du b/tests/variables/import.du index 6c8d56b6..2e51b22e 100644 --- a/tests/variables/import.du +++ b/tests/variables/import.du @@ -7,3 +7,4 @@ import "tests/variables/scope.du"; import "tests/variables/assignment.du"; import "tests/variables/const.du"; +import "tests/variables/list-unpacking.du"; diff --git a/tests/variables/list-unpacking.du b/tests/variables/list-unpacking.du new file mode 100644 index 00000000..93a021ad --- /dev/null +++ b/tests/variables/list-unpacking.du @@ -0,0 +1,29 @@ +/** +* list-unpacking.du +* +* Testing list unpacking for assignment +*/ + +var [a, b, c] = [1, 2, 3]; + +assert(a == 1); +assert(b == 2); +assert(c == 3); + +var [d, e, f] = [1 + 1, 2 + 2, 3 + 3]; + +assert(d == 2); +assert(e == 4); +assert(f == 6); + +var list = [1, nil, true, false, "test", ["more tests", "another"], {"key": "value"}]; + +var [x, y, z, x1, y1, z1, x2] = list; + +assert(x == 1); +assert(y == nil); +assert(z == true); +assert(x1 == false); +assert(y1 == "test"); +assert(z1 == ["more tests", "another"]); +assert(x2 == {"key": "value"}); From 7022a31e04408a7ad70158095cd0e0b4c5f7e629 Mon Sep 17 00:00:00 2001 From: Anish Jewalikar Date: Thu, 1 Oct 2020 12:53:47 +0530 Subject: [PATCH 04/61] Implement list sorting for numbers. --- c/datatypes/lists.c | 67 +++++++++++++++++++++++++++++++++++++++++++++ tests/lists/sort.du | 33 ++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 tests/lists/sort.du diff --git a/c/datatypes/lists.c b/c/datatypes/lists.c index e990ec00..8cdc1cc0 100644 --- a/c/datatypes/lists.c +++ b/c/datatypes/lists.c @@ -1,3 +1,5 @@ +#include + #include "lists.h" static Value toStringList(VM *vm, int argCount, Value *args) { @@ -288,6 +290,70 @@ static Value copyListDeep(VM *vm, int argCount, Value *args) { return OBJ_VAL(newList); } + +static int partition(ObjList* arr, int start, int end) { + int pivot_index = (int)floor(start + end) / 2; + + double pivot = AS_NUMBER(arr->values.values[pivot_index]); + + int i = start - 1; + int j = end + 1; + + for (;;) { + do { + i = i + 1; + } while(AS_NUMBER(arr->values.values[i]) < pivot); + + do { + j = j - 1; + } while(AS_NUMBER(arr->values.values[j]) > pivot); + + if (i >= j) { + return j; + } + + // Swap arr[i] with arr[j] + Value temp = arr->values.values[i]; + + arr->values.values[i] = arr->values.values[j]; + arr->values.values[j] = temp; + } +} + +// Implementation of Quick Sort using the Hoare +// Partition scheme. +// Best Case O(n log n) +// Worst Case O(n^2) (If the list is already sorted.) +static void quickSort(ObjList* arr, int start, int end) { + if (start < end) { + int part = partition(arr, start, end); + + quickSort(arr, start, part); + quickSort(arr, part + 1, end); + } +} + +static Value sortList(VM *vm, int argCount, Value *args) { + if (argCount != 0) { + runtimeError(vm, "sort() takes no arguments (%d given)", argCount); + return EMPTY_VAL; + } + + ObjList* list = AS_LIST(args[0]); + + // Check if all the list elements are indeed numbers. + for (int i = 0; i < list->values.count; i++) { + if (!IS_NUMBER(list->values.values[i])) { + runtimeError(vm, "sort() takes lists with numbers (index %d was not a number)", i); + return EMPTY_VAL; + } + } + + quickSort(list, 0, list->values.count - 1); + + return NIL_VAL; +} + void declareListMethods(VM *vm) { defineNative(vm, &vm->listMethods, "toString", toStringList); defineNative(vm, &vm->listMethods, "len", lenList); @@ -301,4 +367,5 @@ void declareListMethods(VM *vm) { defineNative(vm, &vm->listMethods, "copy", copyListShallow); defineNative(vm, &vm->listMethods, "deepCopy", copyListDeep); defineNative(vm, &vm->listMethods, "toBool", boolNative); // Defined in util + defineNative(vm, &vm->listMethods, "sort", sortList); } diff --git a/tests/lists/sort.du b/tests/lists/sort.du new file mode 100644 index 00000000..02f5a038 --- /dev/null +++ b/tests/lists/sort.du @@ -0,0 +1,33 @@ +/** + * sort.du + * + * Testing list sorting + */ + +var x = [3, 6, 4, 1, 5]; + +// Test basic sorting. +x.sort(); +assert(x == [1, 3, 4, 5, 6]); + +// Test sorting on an already sorted list. +x.sort(); +assert(x == [1, 3, 4, 5, 6]); + +// Test sorting on negative values. +var y = [3, 2, -1, 100, -3, 23, 1, -98]; + +y.sort(); +assert(y == [-98, -3, -1, 1, 2, 3, 23, 100]); + +y.sort(); +assert(y == [-98, -3, -1, 1, 2, 3, 23, 100]); + +// Test sorting on lists containing equal elements +var z = [3, 3, -3, 10, -3]; + +z.sort(); +assert(z == [-3, -3, 3, 3, 10]); + +z.sort(); +assert(z == [-3, -3, 3, 3, 10]); From 5566f2d304a267aaa0d96fec66353fdf9c2fad9c Mon Sep 17 00:00:00 2001 From: Anish Jewalikar Date: Thu, 1 Oct 2020 13:32:11 +0530 Subject: [PATCH 05/61] Optimize for space. Fix test import. --- c/datatypes/lists.c | 14 +++++++++++--- tests/lists/import.du | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/c/datatypes/lists.c b/c/datatypes/lists.c index 8cdc1cc0..04229ea5 100644 --- a/c/datatypes/lists.c +++ b/c/datatypes/lists.c @@ -325,11 +325,19 @@ static int partition(ObjList* arr, int start, int end) { // Best Case O(n log n) // Worst Case O(n^2) (If the list is already sorted.) static void quickSort(ObjList* arr, int start, int end) { - if (start < end) { + while (start < end) { int part = partition(arr, start, end); - quickSort(arr, start, part); - quickSort(arr, part + 1, end); + // Recurse for the smaller halve. + if (part - start < end - part) { + quickSort(arr, start, part); + + start = start + 1; + } else { + quickSort(arr, part + 1, end); + + end = end - 1; + } } } diff --git a/tests/lists/import.du b/tests/lists/import.du index 8f47d81a..9b29689c 100644 --- a/tests/lists/import.du +++ b/tests/lists/import.du @@ -18,3 +18,4 @@ import "tests/lists/len.du"; import "tests/lists/toString.du"; import "tests/lists/toBool.du"; import "tests/lists/plusOperator.du"; +import "tests/lists/sort.du"; From 72492eb42be6badabea71a41b8c049fb1eda3204 Mon Sep 17 00:00:00 2001 From: Anish Jewalikar Date: Thu, 1 Oct 2020 16:52:32 +0530 Subject: [PATCH 06/61] Include the new `sort()` method in docs. Fix a typo in docs. --- docs/docs/collections.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/docs/collections.md b/docs/docs/collections.md index 77b97df7..3a14a6c8 100644 --- a/docs/docs/collections.md +++ b/docs/docs/collections.md @@ -198,13 +198,28 @@ print(list2); // [10, 2] #### list.deepCopy() To get around this, we can deepCopy the list. ```js -var list1 = [[1, 2]; +var list1 = [[1, 2]]; var list2 = list1.deepCopy(); list2[0][0] = 10; print(list1); // [[1, 2]] print(list2); // [[10, 2]] ``` +### Sorting Lists +#### list.sort() + +To sort numeric lists (that is lists that contain only numbers) you can you the method +sort. + +```js +var list1 = [1, -1, 4, 2, 10, 5, 3]; + +print(list1); // [1, -1, 4, 2, 10, 5, 3] +list1.sort(); + +print(list1); // [-1, 1, 2, 3, 4, 5, 10] +``` + ## Dictionaries Dictionaries are a key:value pair data type. Dictu requires that the dictionary key be an immutable type (nil, boolean, number, string), however the value can be any type. From 2d7b9bbe011bbe7d971e8f77233d1facd0523b74 Mon Sep 17 00:00:00 2001 From: Anish Jewalikar Date: Thu, 1 Oct 2020 16:53:38 +0530 Subject: [PATCH 07/61] Fix a typo. --- docs/docs/collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/collections.md b/docs/docs/collections.md index 3a14a6c8..bf84036f 100644 --- a/docs/docs/collections.md +++ b/docs/docs/collections.md @@ -208,7 +208,7 @@ print(list2); // [[10, 2]] ### Sorting Lists #### list.sort() -To sort numeric lists (that is lists that contain only numbers) you can you the method +To sort numeric lists (that is lists that contain only numbers) you can use the method sort. ```js From 443a27ebb042fa37c42f219644907d1b7d996585 Mon Sep 17 00:00:00 2001 From: Shriram bhat Date: Thu, 1 Oct 2020 20:11:50 +0530 Subject: [PATCH 08/61] Adding isdir() --- c/optionals/path.c | 26 +++++++++++++++++++++++++- docs/docs/path.md | 11 +++++++++++ tests/path/import.du | 1 + tests/path/isdir.du | 11 +++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/path/isdir.du diff --git a/c/optionals/path.c b/c/optionals/path.c index 45ceb430..d9e241e4 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -14,6 +14,7 @@ static Value realpathNative(VM *vm, int argCount, Value *args) { char *path = AS_CSTRING(args[0]); + char tmp[PATH_MAX + 1]; if (NULL == realpath(path, tmp)) { SET_ERRNO(GET_SELF_CLASS); @@ -40,6 +41,28 @@ static Value isAbsoluteNative(VM *vm, int argCount, Value *args) { return (IS_DIR_SEPARATOR(path[0]) ? TRUE_VAL : FALSE_VAL); } +static Value isdirNative(VM *vm, int argCount, Value *args) { + if (argCount != 1) { + runtimeError(vm, "isdir() takes 1 argument (%d given)", argCount); + return EMPTY_VAL; + } + + if (!IS_STRING(args[0])) { + runtimeError(vm, "isdir() argument must be a string"); + return EMPTY_VAL; + } + + char *path = AS_CSTRING(args[0]); + struct stat path_stat; + stat(path, &path_stat); + + if (S_ISDIR(path_stat.st_mode)) + return TRUE_VAL; + + return FALSE_VAL; + +} + static Value basenameNative(VM *vm, int argCount, Value *args) { if (argCount != 1) { runtimeError(vm, "basename() takes 1 argument (%d given)", argCount); @@ -180,13 +203,14 @@ ObjModule *createPathClass(VM *vm) { #ifdef HAS_REALPATH defineNative(vm, &module->values, "realpath", realpathNative); defineNativeProperty(vm, &module->values, "errno", NUMBER_VAL(0)); - defineNative(vm, &module->values, "strerror", strerrorNative); // only realpath uset errno + defineNative(vm, &module->values, "strerror", strerrorNative); // only realpath uses errno #endif defineNative(vm, &module->values, "isAbsolute", isAbsoluteNative); defineNative(vm, &module->values, "basename", basenameNative); defineNative(vm, &module->values, "extname", extnameNative); defineNative(vm, &module->values, "dirname", dirnameNative); defineNative(vm, &module->values, "exists", existsNative); + defineNative(vm, &module->values, "isdir", isdirNative); defineNativeProperty(vm, &module->values, "delimiter", OBJ_VAL( copyString(vm, PATH_DELIMITER_AS_STRING, PATH_DELIMITER_STRLEN))); diff --git a/docs/docs/path.md b/docs/docs/path.md index e37d2427..e4250f3b 100644 --- a/docs/docs/path.md +++ b/docs/docs/path.md @@ -92,3 +92,14 @@ Returns a boolean whether a file exists at a given path. ```js Path.exists("some/path/to/a/file.du"); // true ``` + +### Path.isdir(string) + +Checks whether a given path points to a directory or not. + +**Note:** This is not available on windows systems yet. + +```js +Path.isdir("/usr/bin/"); //true +``` + diff --git a/tests/path/import.du b/tests/path/import.du index 01fc9206..d9f0581b 100644 --- a/tests/path/import.du +++ b/tests/path/import.du @@ -10,3 +10,4 @@ import "tests/path/extname.du"; import "tests/path/isAbsolute.du"; import "tests/path/realpath.du"; import "tests/path/exists.du"; +import "tests/path/isdir.du"; \ No newline at end of file diff --git a/tests/path/isdir.du b/tests/path/isdir.du new file mode 100644 index 00000000..33a733a9 --- /dev/null +++ b/tests/path/isdir.du @@ -0,0 +1,11 @@ +/** + * isAbsolute.du + * + * Testing Path.isdir() + * + * Returns true if the given string is a path to a directory, else false. (Linux only) + */ +import Path; + +assert(Path.isdir ("/usr/bin") == true); +assert(Path.isdir ("/home/") ==true); \ No newline at end of file From a44ebd7639722cb7be5ff0f421040553b128a773 Mon Sep 17 00:00:00 2001 From: Shriram Bhat <48955393+artorias111@users.noreply.github.com> Date: Thu, 1 Oct 2020 20:21:51 +0530 Subject: [PATCH 09/61] Update path.c --- c/optionals/path.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/optionals/path.c b/c/optionals/path.c index d9e241e4..1db8e8fb 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -14,7 +14,6 @@ static Value realpathNative(VM *vm, int argCount, Value *args) { char *path = AS_CSTRING(args[0]); - char tmp[PATH_MAX + 1]; if (NULL == realpath(path, tmp)) { SET_ERRNO(GET_SELF_CLASS); From 4aca12c455e52c340d7c5427745daad2e52ab5fb Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Thu, 1 Oct 2020 18:21:03 +0100 Subject: [PATCH 10/61] Add a false assertion to the isdir test --- tests/path/isdir.du | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/path/isdir.du b/tests/path/isdir.du index 33a733a9..4c052a7a 100644 --- a/tests/path/isdir.du +++ b/tests/path/isdir.du @@ -7,5 +7,6 @@ */ import Path; -assert(Path.isdir ("/usr/bin") == true); -assert(Path.isdir ("/home/") ==true); \ No newline at end of file +assert(Path.isdir("/usr/bin") == true); +assert(Path.isdir("/home/") == true); +assert(Path.isdir("tests/runTests.du") == false); \ No newline at end of file From a7319ca4df89a465f09b7203578ed247e72ebb6c Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Thu, 1 Oct 2020 19:16:17 +0100 Subject: [PATCH 11/61] Do not pop closure from stack --- c/vm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/vm.c b/c/vm.c index 7d207a2f..f96d3dc3 100644 --- a/c/vm.c +++ b/c/vm.c @@ -1126,7 +1126,6 @@ static InterpretResult run(VM *vm) { if (function == NULL) return INTERPRET_COMPILE_ERROR; push(vm, OBJ_VAL(function)); ObjClosure *closure = newClosure(vm, function); - pop(vm); frame->ip = ip; call(vm, closure, 0); From 52fdfcdb0e43e4efac57c67dd483f573cd475a97 Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Thu, 1 Oct 2020 19:19:03 +0100 Subject: [PATCH 12/61] Push closure to stack --- c/vm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/c/vm.c b/c/vm.c index f96d3dc3..d92c77f5 100644 --- a/c/vm.c +++ b/c/vm.c @@ -1126,6 +1126,9 @@ static InterpretResult run(VM *vm) { if (function == NULL) return INTERPRET_COMPILE_ERROR; push(vm, OBJ_VAL(function)); ObjClosure *closure = newClosure(vm, function); + pop(vm); + + push(vm, OBJ_VAL(closure)); frame->ip = ip; call(vm, closure, 0); From f74ebe979e050bb49bca83ebd7dd8f78221f45ea Mon Sep 17 00:00:00 2001 From: Anish Jewalikar Date: Fri, 2 Oct 2020 12:01:27 +0530 Subject: [PATCH 13/61] Add support for underscores as separators for large numbers. --- c/compiler.c | 22 +++++++++++++++++++++- c/scanner.c | 2 +- tests/maths/maths.du | 1 + tests/number/toBool.du | 1 + tests/number/toString.du | 4 ++++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/c/compiler.c b/c/compiler.c index 9e733107..c51594fd 100644 --- a/c/compiler.c +++ b/c/compiler.c @@ -670,8 +670,28 @@ static void grouping(Compiler *compiler, bool canAssign) { static void number(Compiler *compiler, bool canAssign) { UNUSED(canAssign); - double value = strtod(compiler->parser->previous.start, NULL); + // We allocate the whole range for the worst case. + char* buffer = (char *)calloc(compiler->parser->previous.length, sizeof(char)); + char* current = buffer; + + // Strip it of any underscores. + for(int i = 0; i < compiler->parser->previous.length; i++) { + char c = compiler->parser->previous.start[i]; + + if (c != '_') { + *(current++) = c; + } + } + + // Terminate the string with a null character. + *current = '\0'; + + // Parse the string. + double value = strtod(buffer, NULL); emitConstant(compiler, NUMBER_VAL(value)); + + // Free the calloc'd buffer. + free(buffer); } static void or_(Compiler *compiler, bool canAssign) { diff --git a/c/scanner.c b/c/scanner.c index f33bda46..250da4c0 100644 --- a/c/scanner.c +++ b/c/scanner.c @@ -280,7 +280,7 @@ static Token identifier() { } static Token number() { - while (isDigit(peek())) advance(); + while (isDigit(peek()) || peek() == '_') advance(); // Look for a fractional part. if (peek() == '.' && isDigit(peekNext())) { diff --git a/tests/maths/maths.du b/tests/maths/maths.du index 6b8e8af7..c5bfe823 100644 --- a/tests/maths/maths.du +++ b/tests/maths/maths.du @@ -28,6 +28,7 @@ assert(Math.abs(-18) == 18); assert(Math.sqrt(25) == 5); assert(Math.sqrt(100) == 10); assert(Math.sqrt(20) == 4.47213595499958); +assert(Math.sqrt(100_00) == 1_00); assert(Math.PI == 3.14159265358979); assert(Math.e == 2.71828182845905); \ No newline at end of file diff --git a/tests/number/toBool.du b/tests/number/toBool.du index 866c7576..3b8692de 100644 --- a/tests/number/toBool.du +++ b/tests/number/toBool.du @@ -9,3 +9,4 @@ assert(1.toBool() == true); assert(0.toBool() == false); assert(11.1.toBool() == true); +assert(11_1.1.toBool() == true); \ No newline at end of file diff --git a/tests/number/toString.du b/tests/number/toString.du index 25d8b675..d95fb40c 100644 --- a/tests/number/toString.du +++ b/tests/number/toString.du @@ -12,4 +12,8 @@ assert(11.1.toString() == "11.1"); var testnum = 123; assert(testnum.toString() == "123"); +// Check underscore parsing. +assert(100_000.toString() == "100000"); +assert(100_001.901.toString() == "100001.901"); + /* TODO: add more */ From 882125a72edeee9caf2d387191ea633a5264676a Mon Sep 17 00:00:00 2001 From: Anish Jewalikar Date: Fri, 2 Oct 2020 12:06:51 +0530 Subject: [PATCH 14/61] Fix a bug in number parsing. --- c/compiler.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/c/compiler.c b/c/compiler.c index c51594fd..2bfb51f0 100644 --- a/c/compiler.c +++ b/c/compiler.c @@ -671,7 +671,8 @@ static void number(Compiler *compiler, bool canAssign) { UNUSED(canAssign); // We allocate the whole range for the worst case. - char* buffer = (char *)calloc(compiler->parser->previous.length, sizeof(char)); + // Also account for the null-byte. + char* buffer = (char *)malloc((compiler->parser->previous.length + 1) * sizeof(char)); char* current = buffer; // Strip it of any underscores. @@ -690,7 +691,7 @@ static void number(Compiler *compiler, bool canAssign) { double value = strtod(buffer, NULL); emitConstant(compiler, NUMBER_VAL(value)); - // Free the calloc'd buffer. + // Free the malloc'd buffer. free(buffer); } From 195ea7aaecf10a60a1a225357012a0f73b9cc6e1 Mon Sep 17 00:00:00 2001 From: Anish Jewalikar Date: Fri, 2 Oct 2020 15:41:57 +0530 Subject: [PATCH 15/61] Make the behaviour consistent. --- c/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/scanner.c b/c/scanner.c index 250da4c0..d32fa613 100644 --- a/c/scanner.c +++ b/c/scanner.c @@ -287,7 +287,7 @@ static Token number() { // Consume the "." advance(); - while (isDigit(peek())) advance(); + while (isDigit(peek()) || peek() == '_') advance(); } return makeToken(TOKEN_NUMBER); From 117dd9ab9295c46762841402b1964db754dc8fca Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Fri, 2 Oct 2020 22:35:29 +0100 Subject: [PATCH 16/61] Fix list unpacking and add tests for local scoping --- c/compiler.c | 29 +++++++++++++++--------- c/vm.c | 2 +- tests/variables/list-unpacking.du | 37 +++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/c/compiler.c b/c/compiler.c index d188dd36..aa06bc05 100644 --- a/c/compiler.c +++ b/c/compiler.c @@ -370,13 +370,13 @@ static void addLocal(Compiler *compiler, Token name) { // Allocates a local slot for the value currently on the stack, if // we're in a local scope. -static void declareVariable(Compiler *compiler) { +static void declareVariable(Compiler *compiler, Token *name) { // Global variables are implicitly declared. if (compiler->scopeDepth == 0) return; // See if a local variable with this name is already declared in this // scope. - Token *name = &compiler->parser->previous; + // Token *name = &compiler->parser->previous; for (int i = compiler->localCount - 1; i >= 0; i--) { Local *local = &compiler->locals[i]; if (local->depth != -1 && local->depth < compiler->scopeDepth) break; @@ -398,7 +398,7 @@ static uint8_t parseVariable(Compiler *compiler, const char *errorMessage, bool return identifierConstant(compiler, &compiler->parser->previous); } - declareVariable(compiler); + declareVariable(compiler, &compiler->parser->previous); return 0; } @@ -1291,7 +1291,7 @@ static void parseClassBody(Compiler *compiler) { static void classDeclaration(Compiler *compiler) { consume(compiler, TOKEN_IDENTIFIER, "Expect class name."); uint8_t nameConstant = identifierConstant(compiler, &compiler->parser->previous); - declareVariable(compiler); + declareVariable(compiler, &compiler->parser->previous); ClassCompiler classCompiler; setupClassCompiler(compiler, &classCompiler, false); @@ -1334,7 +1334,7 @@ static void abstractClassDeclaration(Compiler *compiler) { consume(compiler, TOKEN_IDENTIFIER, "Expect class name."); uint8_t nameConstant = identifierConstant(compiler, &compiler->parser->previous); - declareVariable(compiler); + declareVariable(compiler, &compiler->parser->previous); ClassCompiler classCompiler; setupClassCompiler(compiler, &classCompiler, true); @@ -1372,7 +1372,7 @@ static void abstractClassDeclaration(Compiler *compiler) { static void traitDeclaration(Compiler *compiler) { consume(compiler, TOKEN_IDENTIFIER, "Expect trait name."); uint8_t nameConstant = identifierConstant(compiler, &compiler->parser->previous); - declareVariable(compiler); + declareVariable(compiler, &compiler->parser->previous); ClassCompiler classCompiler; setupClassCompiler(compiler, &classCompiler, false); @@ -1398,11 +1398,12 @@ static void funDeclaration(Compiler *compiler) { static void varDeclaration(Compiler *compiler, bool constant) { if (match(compiler, TOKEN_LEFT_BRACKET)) { - uint8_t variables[255]; + Token variables[255]; int varCount = 0; do { - variables[varCount] = parseVariable(compiler, "Expect variable name.", constant); + consume(compiler, TOKEN_IDENTIFIER, "Expect variable name."); + variables[varCount] = compiler->parser->previous; varCount++; } while (match(compiler, TOKEN_COMMA)); @@ -1413,8 +1414,16 @@ static void varDeclaration(Compiler *compiler, bool constant) { emitBytes(compiler, OP_UNPACK_LIST, varCount); - for (int i = 0; i < varCount; ++i) { - defineVariable(compiler, variables[i], constant); + if (compiler->scopeDepth == 0) { + for (int i = varCount - 1; i >= 0; --i) { + uint8_t identifier = identifierConstant(compiler, &variables[i]); + defineVariable(compiler, identifier, constant); + } + } else { + for (int i = 0; i < varCount; ++i) { + declareVariable(compiler, &variables[i]); + defineVariable(compiler, 0, constant); + } } } else { do { diff --git a/c/vm.c b/c/vm.c index 4662a3b5..f2e8024f 100644 --- a/c/vm.c +++ b/c/vm.c @@ -1217,7 +1217,7 @@ static InterpretResult run(VM *vm) { return INTERPRET_RUNTIME_ERROR; } - for (int i = list->values.count; i >= 0; --i) { + for (int i = 0; i < list->values.count; ++i) { push(vm, list->values.values[i]); } diff --git a/tests/variables/list-unpacking.du b/tests/variables/list-unpacking.du index 93a021ad..008306c9 100644 --- a/tests/variables/list-unpacking.du +++ b/tests/variables/list-unpacking.du @@ -27,3 +27,40 @@ assert(x1 == false); assert(y1 == "test"); assert(z1 == ["more tests", "another"]); assert(x2 == {"key": "value"}); + +// Test it wil locals +{ + var [x, y, z, x1, y1, z1, x2] = list; + + assert(x == 1); + assert(y == nil); + assert(z == true); + assert(x1 == false); + assert(y1 == "test"); + assert(z1 == ["more tests", "another"]); + assert(x2 == {"key": "value"}); + + // Test with completely new identifiers + var [x10, y10, z10, x20, y20, z20, x30] = list; + + assert(x10 == 1); + assert(y10 == nil); + assert(z10 == true); + assert(x20 == false); + assert(y20 == "test"); + assert(z20 == ["more tests", "another"]); + assert(x30 == {"key": "value"}); + + { + // Test nested scope just to make sure + var [x, y, z, x1, y1, z1, x2] = list; + + assert(x == 1); + assert(y == nil); + assert(z == true); + assert(x1 == false); + assert(y1 == "test"); + assert(z1 == ["more tests", "another"]); + assert(x2 == {"key": "value"}); + } +} From a9af7af05f9a2cbc69261ded4369d7c2c7372514 Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Sat, 3 Oct 2020 16:27:53 +0100 Subject: [PATCH 17/61] Better error message for list unpacking on already defined variables --- c/compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/compiler.c b/c/compiler.c index aa06bc05..bdc32941 100644 --- a/c/compiler.c +++ b/c/compiler.c @@ -381,7 +381,7 @@ static void declareVariable(Compiler *compiler, Token *name) { Local *local = &compiler->locals[i]; if (local->depth != -1 && local->depth < compiler->scopeDepth) break; if (identifiersEqual(name, &local->name)) { - error(compiler->parser, "Variable with this name already declared in this scope."); + errorAt(compiler->parser, name, "Variable with this name already declared in this scope."); } } From 90262361ddd836cd25d9b9f8a460987f3fb5b144 Mon Sep 17 00:00:00 2001 From: The Great Cookie Machine <39784551+TheGreatCookieMachine@users.noreply.github.com> Date: Sat, 3 Oct 2020 20:02:44 -0700 Subject: [PATCH 18/61] Allow Dictu to compile on Windows --- CMakeLists.txt | 42 ++++++++++++++++++++++++ c/common.h | 7 ++++ c/datatypes/files.c | 10 ++++-- c/datatypes/number.c | 20 +++++++++++- c/linenoise.c | 2 ++ c/main.c | 60 ++++++++++++++++++++++++++++++++-- c/memory.h | 2 -- c/opcodes.h | 2 +- c/optionals/c.c | 12 ++++++- c/optionals/c.h | 2 ++ c/optionals/datetime.c | 31 +++++++++++++++++- c/optionals/env.c | 15 +++++++++ c/optionals/http.c | 2 +- c/optionals/json.c | 2 +- c/optionals/jsonParseLib.c | 2 +- c/optionals/optionals.c | 7 ++++ c/optionals/optionals.h | 9 ++---- c/optionals/path.c | 6 ++-- c/optionals/path.h | 6 +++- c/optionals/socket.c | 20 ++++++++++++ c/optionals/system.c | 9 ++++-- c/optionals/system.h | 7 ++-- c/windowsapi.h | 10 ++++++ docs/docs/datetime.md | 2 ++ docs/docs/system.md | 12 +++++++ tests/datetime/strftime.du | 2 +- tests/datetime/strptime.du | 66 ++++++++++++++++++++------------------ tests/files/seek.du | 4 +-- tests/system/mkdir.du | 8 +++-- tests/system/process.du | 14 ++++---- tests/system/remove.du | 8 +++-- tests/system/setCWD.du | 6 +++- 32 files changed, 331 insertions(+), 76 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 c/windowsapi.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..db86dd18 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.18.0) +project(Dictu C) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + +set(DISABLE_HTTP OFF CACHE BOOL "Determines if HTTPS based features are compiled. HTTPS based features require cURL.") +set(DISABLE_LINENOISE OFF CACHE BOOL "Determines if the REPL uses linenoise. Linenoise requires termios.") + +file(GLOB_RECURSE sources "c/*.c") +file(GLOB_RECURSE headers "c/*.h") +set(libraries) + +if(DISABLE_HTTP) + list(FILTER sources EXCLUDE REGEX "http.c") + list(FILTER headers EXCLUDE REGEX "http.h") + add_compile_definitions(DISABLE_HTTP) +else() + list(APPEND libraries curl) +endif() + +if(DISABLE_LINENOISE) + add_compile_definitions(DISABLE_LINENOISE) +endif() + +if(WIN32) + # ws2_32 is required for winsock2.h to work correctly + list(APPEND libraries ws2_32) +else() +list(APPEND libraries m) +endif() + +if(MSVC) + add_compile_options() +else() + add_compile_options(-Wall -Wextra -Werror -Wshadow -Wunused-function -Wunused-macros) +endif() + +add_executable(${PROJECT_NAME} ${sources} ${headers}) + +target_link_libraries(${PROJECT_NAME} ${libraries}) diff --git a/c/common.h b/c/common.h index f7bfe314..d3ffe937 100644 --- a/c/common.h +++ b/c/common.h @@ -11,7 +11,9 @@ #define DEBUG_TRACE_GC #define DEBUG_TRACE_MEM +#ifndef _MSC_VER #define COMPUTED_GOTO +#endif #undef DEBUG_PRINT_CODE #undef DEBUG_TRACE_EXECUTION @@ -23,6 +25,11 @@ #define UINT8_COUNT (UINT8_MAX + 1) +// MSVC does not support VLAs in C99 but also doesn't define __STDC_NO_VLA__. As such we must check _MSC_VER separately. +#if (defined(__STDC__) && !defined(__STDC_VERSION__)) || defined(__STDC_NO_VLA__) || defined(_MSC_VER) +#define NO_VLA +#endif + typedef struct _vm VM; #endif diff --git a/c/datatypes/files.c b/c/datatypes/files.c index 1b6efd53..98454800 100644 --- a/c/datatypes/files.c +++ b/c/datatypes/files.c @@ -79,14 +79,14 @@ static Value readFullFile(VM *vm, int argCount, Value *args) { } size_t bytesRead = fread(buffer, sizeof(char), fileSize, file->file); - if (bytesRead < fileSize) { + if (bytesRead < fileSize && !feof(file->file)) { free(buffer); runtimeError(vm, "Could not read file \"%s\".\n", file->path); return EMPTY_VAL; } buffer[bytesRead] = '\0'; - Value ret = OBJ_VAL(copyString(vm, buffer, fileSize)); + Value ret = OBJ_VAL(copyString(vm, buffer, bytesRead)); free(buffer); return ret; @@ -154,6 +154,12 @@ static Value seekFile(VM *vm, int argCount, Value *args) { int offset = AS_NUMBER(args[1]); ObjFile *file = AS_FILE(args[0]); + + if (offset != 0 && !strstr(file->openType, "b")) { + runtimeError(vm, "seek() may not have non-zero offset if file is opened in text mode"); + return EMPTY_VAL; + } + fseek(file->file, offset, seekType); return NIL_VAL; diff --git a/c/datatypes/number.c b/c/datatypes/number.c index 44972d51..8e20b62d 100644 --- a/c/datatypes/number.c +++ b/c/datatypes/number.c @@ -1,6 +1,8 @@ #include "number.h" #include "../vm.h" +#include + static Value toStringNumber(VM *vm, int argCount, Value *args) { if (argCount != 0) { runtimeError(vm, "toString() takes no arguments (%d given)", argCount); @@ -9,9 +11,25 @@ static Value toStringNumber(VM *vm, int argCount, Value *args) { double number = AS_NUMBER(args[0]); int numberStringLength = snprintf(NULL, 0, "%.15g", number) + 1; + + #ifdef NO_VLA + char *numberString = malloc(numberStringLength); + if (numberString == NULL) { + runtimeError(vm, "Memory error on toString()!"); + return EMPTY_VAL; + } + #else char numberString[numberStringLength]; + #endif + snprintf(numberString, numberStringLength, "%.15g", number); - return OBJ_VAL(copyString(vm, numberString, numberStringLength - 1)); + Value value = OBJ_VAL(copyString(vm, numberString, numberStringLength - 1)); + + #ifdef NO_VLA + free(numberString); + #endif + + return value; } void declareNumberMethods(VM *vm) { diff --git a/c/linenoise.c b/c/linenoise.c index ea1852c9..d4c0f169 100644 --- a/c/linenoise.c +++ b/c/linenoise.c @@ -103,6 +103,7 @@ * */ +#ifndef DISABLE_LINENOISE #include #include #include @@ -1233,3 +1234,4 @@ int linenoiseHistoryLoad(const char *filename) { fclose(fp); return 0; } +#endif diff --git a/c/main.c b/c/main.c index 58ab1dc7..68074a6a 100644 --- a/c/main.c +++ b/c/main.c @@ -4,16 +4,25 @@ #if (defined(__unix__) || defined(unix)) && !defined(USG) #include +#elif defined(_WIN32) +#include "windowsapi.h" + +void cleanupSockets(void) { + // Calls WSACleanup until an error occurs. + // Avoids issues if WSAStartup is called multiple times. + while (!WSACleanup()); +} #endif #include "common.h" #include "vm.h" #include "util.h" -#include "linenoise.h" - #define VERSION "Dictu Version: 0.10.0\n" +#ifndef DISABLE_LINENOISE +#include "linenoise.h" + static bool replCountBraces(char *line) { int leftBraces = 0; int rightBraces = 0; @@ -62,6 +71,7 @@ static bool replCountQuotes(char *line) { return singleQuotes % 2 == 0 && doubleQuotes % 2 == 0; } +#endif static void repl(VM *vm, int argc, const char *argv[]) { UNUSED(argc); UNUSED(argv); @@ -69,6 +79,7 @@ static void repl(VM *vm, int argc, const char *argv[]) { printf(VERSION); char *line; + #ifndef DISABLE_LINENOISE linenoiseHistoryLoad("history.txt"); while((line = linenoise(">>> ")) != NULL) { @@ -105,6 +116,44 @@ static void repl(VM *vm, int argc, const char *argv[]) { free(line); free(fullLine); } + #else + #define BUFFER_SIZE 8 + line = calloc(BUFFER_SIZE, sizeof(char)); + if (line == NULL) { + printf("Unable to allocate memory\n"); + exit(71); + } + size_t lineLength = 0; + size_t lineMemory = BUFFER_SIZE; + + while (true) { + printf(">>> "); + + char buffer[BUFFER_SIZE]; + while (fgets(buffer, BUFFER_SIZE, stdin) != NULL) { + while (lineLength + BUFFER_SIZE > lineMemory) { + lineMemory *= 2; + line = realloc(line, lineMemory); + if (line == NULL) { + printf("Unable to allocate memory\n"); + exit(71); + } + } + strcat(line, buffer); + lineLength += BUFFER_SIZE; + if (strlen(buffer) != BUFFER_SIZE - 1 || buffer[BUFFER_SIZE-2] == '\n') { + break; + } + } + + interpret(vm, line); + lineLength = 0; + line[0] = '\0'; + } + + #undef BUFFER_SIZE + free(line); + #endif } static void runFile(VM *vm, int argc, const char *argv[]) { @@ -119,6 +168,13 @@ static void runFile(VM *vm, int argc, const char *argv[]) { } int main(int argc, const char *argv[]) { + #ifdef _WIN32 + atexit(cleanupSockets); + WORD versionWanted = MAKEWORD(2, 2); + WSADATA wsaData; + WSAStartup(versionWanted, &wsaData); + #endif + VM *vm = initVM(argc == 1, argc >= 2 ? argv[1] : "repl", argc, argv); if (argc == 1) { diff --git a/c/memory.h b/c/memory.h index b50e1f89..1bb068b7 100644 --- a/c/memory.h +++ b/c/memory.h @@ -1,8 +1,6 @@ #ifndef dictu_memory_h #define dictu_memory_h -#include - #include "object.h" #include "common.h" diff --git a/c/opcodes.h b/c/opcodes.h index 4e9d1131..80f05dca 100644 --- a/c/opcodes.h +++ b/c/opcodes.h @@ -61,4 +61,4 @@ OPCODE(BITWISE_AND) OPCODE(BITWISE_XOR) OPCODE(BITWISE_OR) OPCODE(POP_REPL) -OPCODE(BREAK) \ No newline at end of file +OPCODE(BREAK) diff --git a/c/optionals/c.c b/c/optionals/c.c index 8df929ab..f971341a 100644 --- a/c/optionals/c.c +++ b/c/optionals/c.c @@ -1,5 +1,9 @@ #include "c.h" +#ifdef _WIN32 +#define strerror_r(ERRNO, BUF, LEN) strerror_s(BUF, LEN, ERRNO) +#endif + Value strerrorGeneric(VM *vm, int error) { if (error <= 0) { runtimeError(vm, "strerror() argument should be > 0"); @@ -39,7 +43,7 @@ Value strerrorNative(VM *vm, int argCount, Value *args) { if (argCount == 1) { error = AS_NUMBER(args[0]); } else { - error = AS_NUMBER(GET_ERRNO(GET_SELF_CLASS)); + error = AS_NUMBER(getErrno(vm, GET_SELF_CLASS)); } return strerrorGeneric(vm, error); @@ -174,7 +178,9 @@ void createCClass(VM *vm) { defineNativeProperty(vm, &module->values, "ECOMM", NUMBER_VAL(ECOMM)); #endif defineNativeProperty(vm, &module->values, "EPROTO", NUMBER_VAL(EPROTO)); +#ifdef EMULTIHOP defineNativeProperty(vm, &module->values, "EMULTIHOP", NUMBER_VAL(EMULTIHOP)); +#endif #ifdef EDOTDOT defineNativeProperty(vm, &module->values, "EDOTDOT", NUMBER_VAL(EDOTDOT)); #endif @@ -252,7 +258,9 @@ void createCClass(VM *vm) { defineNativeProperty(vm, &module->values, "EHOSTUNREACH", NUMBER_VAL(EHOSTUNREACH)); defineNativeProperty(vm, &module->values, "EALREADY", NUMBER_VAL(EALREADY)); defineNativeProperty(vm, &module->values, "EINPROGRESS", NUMBER_VAL(EINPROGRESS)); +#ifdef ESTALE defineNativeProperty(vm, &module->values, "ESTALE", NUMBER_VAL(ESTALE)); +#endif #ifdef EUCLEAN defineNativeProperty(vm, &module->values, "EUCLEAN", NUMBER_VAL(EUCLEAN)); #endif @@ -268,7 +276,9 @@ void createCClass(VM *vm) { #ifdef EREMOTEIO defineNativeProperty(vm, &module->values, "EREMOTEIO", NUMBER_VAL(EREMOTEIO)); #endif +#ifdef EDQUOT defineNativeProperty(vm, &module->values, "EDQUOT", NUMBER_VAL(EDQUOT)); +#endif #ifdef ENOMEDIUM defineNativeProperty(vm, &module->values, "ENOMEDIUM", NUMBER_VAL(ENOMEDIUM)); #endif diff --git a/c/optionals/c.h b/c/optionals/c.h index 9dc20142..fa9c272c 100644 --- a/c/optionals/c.h +++ b/c/optionals/c.h @@ -25,6 +25,8 @@ #ifdef __APPLE__ #define LAST_ERROR 106 +#elif defined(_WIN32) +#define LAST_ERROR EWOULDBLOCK #else #define LAST_ERROR EHWPOISON #endif diff --git a/c/optionals/datetime.c b/c/optionals/datetime.c index 65f87abd..2f14a91b 100644 --- a/c/optionals/datetime.c +++ b/c/optionals/datetime.c @@ -1,5 +1,17 @@ +#include +#include + #include "datetime.h" +#ifdef _WIN32 +#define localtime_r(TIMER, BUF) localtime_s(BUF, TIMER) +// Assumes length of BUF is 26 +#define asctime_r(TIME_PTR, BUF) (asctime_s(BUF, 26, TIME_PTR), BUF) +#define gmtime_r(TIMER, BUF) gmtime_s(BUF, TIMER) +#else +#define HAS_STRPTIME +#endif + static Value nowNative(VM *vm, int argCount, Value *args) { UNUSED(args); @@ -72,7 +84,16 @@ static Value strftimeNative(VM *vm, int argCount, Value *args) { struct tm tictoc; int len = (format->length > 128 ? format->length * 4 : 128); - char buffer[len], *point = buffer; + #ifdef NO_VLA + char *buffer = malloc(len); + if (buffer == NULL) { + runtimeError(vm, "Memory error on toString()!"); + return EMPTY_VAL; + } + #else + char buffer[len]; + #endif + char *point = buffer; gmtime_r(&t, &tictoc); @@ -111,10 +132,15 @@ static Value strftimeNative(VM *vm, int argCount, Value *args) { theend: if (buffer != point) free(point); + + #ifdef NO_VLA + free(buffer); + #endif return OBJ_VAL(res); } +#ifdef HAS_STRPTIME static Value strptimeNative(VM *vm, int argCount, Value *args) { if (argCount != 2) { runtimeError(vm, "strptime() takes 2 arguments (%d given)", argCount); @@ -138,6 +164,7 @@ static Value strptimeNative(VM *vm, int argCount, Value *args) { return NUMBER_VAL((double) mktime(&tictoc)); } +#endif ObjModule *createDatetimeClass(VM *vm) { ObjString *name = copyString(vm, "Datetime", 8); @@ -151,7 +178,9 @@ ObjModule *createDatetimeClass(VM *vm) { defineNative(vm, &module->values, "now", nowNative); defineNative(vm, &module->values, "nowUTC", nowUTCNative); defineNative(vm, &module->values, "strftime", strftimeNative); + #ifdef HAS_STRPTIME defineNative(vm, &module->values, "strptime", strptimeNative); + #endif pop(vm); pop(vm); diff --git a/c/optionals/env.c b/c/optionals/env.c index 21cc28f4..ed85b911 100644 --- a/c/optionals/env.c +++ b/c/optionals/env.c @@ -1,5 +1,20 @@ #include "env.h" +#ifdef _WIN32 +#define unsetenv(NAME) _putenv_s(NAME, "") +int setenv(const char *name, const char *value, int overwrite) { + if (!overwrite && getenv(name) == NULL) { + return 0; + } + + if (_putenv_s(name, value)) { + return -1; + } else { + return 0; + } +} +#endif + static Value get(VM *vm, int argCount, Value *args) { if (argCount != 1) { runtimeError(vm, "get() takes 1 argument (%d given).", argCount); diff --git a/c/optionals/http.c b/c/optionals/http.c index 55194442..6dfc84cb 100644 --- a/c/optionals/http.c +++ b/c/optionals/http.c @@ -10,7 +10,7 @@ static Value strerrorHttpNative(VM *vm, int argCount, Value *args) { if (argCount == 1) { error = AS_NUMBER(args[0]); } else { - error = AS_NUMBER(GET_ERRNO(GET_SELF_CLASS)); + error = AS_NUMBER(getErrno(vm, GET_SELF_CLASS)); } char *error_string = (char *) curl_easy_strerror(error); diff --git a/c/optionals/json.c b/c/optionals/json.c index ae7ab39a..c1954e53 100644 --- a/c/optionals/json.c +++ b/c/optionals/json.c @@ -24,7 +24,7 @@ static Value strerrorJsonNative(VM *vm, int argCount, Value *args) { if (argCount == 1) { error = AS_NUMBER(args[0]); } else { - error = AS_NUMBER(GET_ERRNO(GET_SELF_CLASS)); + error = AS_NUMBER(getErrno(vm, GET_SELF_CLASS)); } if (error == 0) { diff --git a/c/optionals/jsonParseLib.c b/c/optionals/jsonParseLib.c index ad7e3cf9..9e05f8df 100644 --- a/c/optionals/jsonParseLib.c +++ b/c/optionals/jsonParseLib.c @@ -158,7 +158,7 @@ static int new_value (json_state * state, int values_size = sizeof (*value->u.object.values) * value->u.object.length; if (! (value->u.object.values = (json_object_entry *) json_alloc - (state, values_size + ((unsigned long) value->u.object.values), 0)) ) + (state, values_size + ((uintptr_t) value->u.object.values), 0)) ) { return 0; } diff --git a/c/optionals/optionals.c b/c/optionals/optionals.c index f7e0f5a5..55987c7b 100644 --- a/c/optionals/optionals.c +++ b/c/optionals/optionals.c @@ -17,6 +17,13 @@ ObjModule *importBuiltinModule(VM *vm, int index) { return modules[index].module(vm); } +Value getErrno(VM* vm, ObjModule* module) { + Value errno_value = 0; + ObjString *name = copyString(vm, "errno", 5); + tableGet(&module->values, name, &errno_value); + return errno_value; +} + int findBuiltinModule(char *name, int length) { for (int i = 0; modules[i].module != NULL; ++i) { if (strncmp(modules[i].name, name, length) == 0) { diff --git a/c/optionals/optionals.h b/c/optionals/optionals.h index e4272bad..e3ccd7de 100644 --- a/c/optionals/optionals.h +++ b/c/optionals/optionals.h @@ -21,13 +21,6 @@ #define RESET_ERRNO(module_) \ defineNativeProperty(vm, &module_->values, "errno", 0) -#define GET_ERRNO(module_)({ \ - Value errno_value = 0; \ - ObjString *name = copyString(vm, "errno", 5); \ - tableGet(&module_->values, name, &errno_value); \ - errno_value; \ -}) - typedef ObjModule *(*BuiltinModule)(VM *vm); typedef struct { @@ -37,6 +30,8 @@ typedef struct { ObjModule *importBuiltinModule(VM *vm, int index); +Value getErrno(VM* vm, ObjModule* module); + int findBuiltinModule(char *name, int length); #endif //dictu_optionals_h diff --git a/c/optionals/path.c b/c/optionals/path.c index 45ceb430..a11b0188 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -56,12 +56,12 @@ static Value basenameNative(VM *vm, int argCount, Value *args) { int len = PathString->length; - if (!len || (len == 1 && *path != DIR_SEPARATOR)) { + if (!len || (len == 1 && !IS_DIR_SEPARATOR(*path))) { return OBJ_VAL(copyString(vm, "", 0)); } char *p = path + len - 1; - while (p > path && (*(p - 1) != DIR_SEPARATOR)) --p; + while (p > path && !IS_DIR_SEPARATOR(*(p - 1))) --p; return OBJ_VAL(copyString(vm, p, (len - (p - path)))); } @@ -141,7 +141,7 @@ static Value dirnameNative(VM *vm, int argCount, Value *args) { sep--; } - if (sep == path && *sep != DIR_SEPARATOR) { + if (sep == path && !IS_DIR_SEPARATOR(*sep)) { return OBJ_VAL(copyString(vm, ".", 1)); } diff --git a/c/optionals/path.h b/c/optionals/path.h index 12ac6a41..f81176a5 100644 --- a/c/optionals/path.h +++ b/c/optionals/path.h @@ -10,8 +10,8 @@ #endif #ifdef _WIN32 -#include #define DIR_SEPARATOR '\\' +#define DIR_ALT_SEPARATOR '/' #define DIR_SEPARATOR_AS_STRING "\\" #define DIR_SEPARATOR_STRLEN 1 #define PATH_DELIMITER ';' @@ -27,7 +27,11 @@ #define PATH_DELIMITER_STRLEN 1 #endif +#ifdef DIR_ALT_SEPARATOR +#define IS_DIR_SEPARATOR(c) ((c) == DIR_SEPARATOR || (c) == DIR_ALT_SEPARATOR) +#else #define IS_DIR_SEPARATOR(c) (c == DIR_SEPARATOR) +#endif #include "optionals.h" #include "../vm.h" diff --git a/c/optionals/socket.c b/c/optionals/socket.c index cf22340e..54910588 100644 --- a/c/optionals/socket.c +++ b/c/optionals/socket.c @@ -1,8 +1,28 @@ #include "socket.h" #include + +#ifdef _WIN32 +#include "../windowsapi.h" +#include +#define setsockopt(S, LEVEL, OPTNAME, OPTVAL, OPTLEN) setsockopt(S, LEVEL, OPTNAME, (char*)(OPTVAL), OPTLEN) + +#ifndef __MINGW32__ +// Fixes deprecation warning +unsigned long inet_addr_new(const char* cp) { + unsigned long S_addr; + inet_pton(AF_INET, cp, &S_addr); + return S_addr; +} +#define inet_addr(cp) inet_addr_new(cp) +#endif + +#define write(fd, buffer, count) _write(fd, buffer, count) +#define close(fd) closesocket(fd) +#else #include #include +#endif static Value createSocket(VM *vm, int argCount, Value *args) { if (argCount != 2) { diff --git a/c/optionals/system.c b/c/optionals/system.c index 3dfc42aa..b85b8204 100644 --- a/c/optionals/system.c +++ b/c/optionals/system.c @@ -1,5 +1,6 @@ #include "system.h" +#ifndef _WIN32 static Value getgidNative(VM *vm, int argCount, Value *args) { UNUSED(args); @@ -65,6 +66,7 @@ static Value getpidNative(VM *vm, int argCount, Value *args) { return NUMBER_VAL(getpid()); } +#endif static Value rmdirNative(VM *vm, int argCount, Value *args) { if (argCount != 1) { @@ -285,9 +287,7 @@ void initArgv(VM *vm, Table *table, int argc, const char *argv[]) { void initPlatform(VM *vm, Table *table) { #ifdef _WIN32 defineNativeProperty(vm, table, "platform", OBJ_VAL(copyString(vm, "windows", 7))); - return; -#endif - +#elif struct utsname u; if (-1 == uname(&u)) { defineNativeProperty(vm, table, "platform", OBJ_VAL(copyString(vm, @@ -298,6 +298,7 @@ void initPlatform(VM *vm, Table *table) { u.sysname[0] = tolower(u.sysname[0]); defineNativeProperty(vm, table, "platform", OBJ_VAL(copyString(vm, u.sysname, strlen(u.sysname)))); +#endif } void createSystemClass(VM *vm, int argc, const char *argv[]) { @@ -310,12 +311,14 @@ void createSystemClass(VM *vm, int argc, const char *argv[]) { * Define System methods */ defineNative(vm, &module->values, "strerror", strerrorNative); +#ifndef _WIN32 defineNative(vm, &module->values, "getgid", getgidNative); defineNative(vm, &module->values, "getegid", getegidNative); defineNative(vm, &module->values, "getuid", getuidNative); defineNative(vm, &module->values, "geteuid", geteuidNative); defineNative(vm, &module->values, "getppid", getppidNative); defineNative(vm, &module->values, "getpid", getpidNative); +#endif defineNative(vm, &module->values, "rmdir", rmdirNative); defineNative(vm, &module->values, "mkdir", mkdirNative); #ifdef HAS_ACCESS diff --git a/c/optionals/system.h b/c/optionals/system.h index b894af63..3c271294 100644 --- a/c/optionals/system.h +++ b/c/optionals/system.h @@ -3,17 +3,18 @@ #include #include -#include #include #include #include #ifdef _WIN32 -#include +#include "../windowsapi.h" +#include #define REMOVE remove -#define MKDIR(d, m) mkdir(d) +#define MKDIR(d, m) ((void)m, mkdir(d)) #else #include +#include #define HAS_ACCESS #define REMOVE unlink #define MKDIR(d, m) mkdir(d, m) diff --git a/c/windowsapi.h b/c/windowsapi.h new file mode 100644 index 00000000..a2c4f579 --- /dev/null +++ b/c/windowsapi.h @@ -0,0 +1,10 @@ +// This is a thin wrapper around certain headers of the windows API which resolves a conflict between winnt.h and the scanner. +// winnt.h adds an enum member called TokenType into the global scope, conflicting with TokenType in the scanner. +// All instances of TokenType within the windows API is replaced by WinntTokenType. +// Window's TokenType is documented here: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_information_class +#ifdef _WIN32 +#define TokenType WinntTokenType +#include +#include +#undef TokenType +#endif diff --git a/docs/docs/datetime.md b/docs/docs/datetime.md index c0b36ae0..6f926b2f 100644 --- a/docs/docs/datetime.md +++ b/docs/docs/datetime.md @@ -91,6 +91,8 @@ Returns a number which is the number of seconds from epoch. `strptime` expects t the first parameter being the date format, see [Datetime formats](#datetime-formats) and the second the date string in the format of the first parameter. +**Note:** This is not available on windows systems. + ```js Datetime.strptime("%Y-%m-%d %H:%M:%S", "2020-01-01 00:00:00"); // 1577836800 ``` diff --git a/docs/docs/system.md b/docs/docs/system.md index 5e02da29..a864fd95 100644 --- a/docs/docs/system.md +++ b/docs/docs/system.md @@ -109,6 +109,8 @@ System.remove(file); Returns the process ID (PID) of the calling process. +**Note:** This is not available on windows systems. + ```js System.getpid(); ``` @@ -117,6 +119,8 @@ System.getpid(); Returns the process ID of the parent of the calling process +**Note:** This is not available on windows systems. + ```js System.getppid(); ``` @@ -125,6 +129,8 @@ System.getppid(); Returns the real user ID of the calling process. +**Note:** This is not available on windows systems. + ```js System.getuid(); ``` @@ -133,6 +139,8 @@ System.getuid(); Returns the effective user ID of the calling process. +**Note:** This is not available on windows systems. + ```js System.geteuid(); ``` @@ -141,6 +149,8 @@ System.geteuid(); Returns the real group ID of the calling process. +**Note:** This is not available on windows systems. + ```js System.getgid(); ``` @@ -149,6 +159,8 @@ System.getgid(); Returns the effective group ID of the calling process. +**Note:** This is not available on windows systems. + ```js System.getegid(); ``` diff --git a/tests/datetime/strftime.du b/tests/datetime/strftime.du index ae9526b7..4247599b 100644 --- a/tests/datetime/strftime.du +++ b/tests/datetime/strftime.du @@ -18,7 +18,7 @@ assert(Datetime.strftime("%d", 1577836800) == "01"); assert(Datetime.strftime("%a", 1577836800) == "Wed"); assert(Datetime.strftime("%A", 1577836800) == "Wednesday"); -assert(Datetime.strftime("%u", 1577836800) == "3"); +assert(Datetime.strftime("%u", 1577836800) == "3" or Datetime.strftime("%u", 1577836800) == ""); assert(Datetime.strftime("%H", 1577836800) == "00"); assert(Datetime.strftime("%M", 1577836800) == "00"); diff --git a/tests/datetime/strptime.du b/tests/datetime/strptime.du index 92bb899a..ee35e7fa 100644 --- a/tests/datetime/strptime.du +++ b/tests/datetime/strptime.du @@ -6,40 +6,42 @@ */ import Datetime; -// 1577836800 is 1/1/2020 at 12:00 am -assert(Datetime.strptime("%Y", "2020") == 1577836800); -assert(Datetime.strptime("%Y-%m", "2020-1") == 1577836800); -assert(Datetime.strptime("%Y-%m", "2020-01") == 1577836800); -assert(Datetime.strptime("%Y-%b", "2020-Jan") == 1577836800); -assert(Datetime.strptime("%Y-%B", "2020-January") == 1577836800); +if (System.platform != "windows") { + // 1577836800 is 1/1/2020 at 12:00 am + assert(Datetime.strptime("%Y", "2020") == 1577836800); + assert(Datetime.strptime("%Y-%m", "2020-1") == 1577836800); + assert(Datetime.strptime("%Y-%m", "2020-01") == 1577836800); + assert(Datetime.strptime("%Y-%b", "2020-Jan") == 1577836800); + assert(Datetime.strptime("%Y-%B", "2020-January") == 1577836800); -assert(Datetime.strptime("%Y-%d", "2020-1") == 1577836800); -assert(Datetime.strptime("%Y-%d", "2020-01") == 1577836800); + assert(Datetime.strptime("%Y-%d", "2020-1") == 1577836800); + assert(Datetime.strptime("%Y-%d", "2020-01") == 1577836800); -assert(Datetime.strptime("%Y-%m-%d", "2020-1-1") == 1577836800); -assert(Datetime.strptime("%Y-%m-%d", "2020-01-1") == 1577836800); -assert(Datetime.strptime("%Y-%b-%d", "2020-Jan-1") == 1577836800); -assert(Datetime.strptime("%Y-%B-%d", "2020-January-1") == 1577836800); -assert(Datetime.strptime("%Y-%m-%d", "2020-1-01") == 1577836800); -assert(Datetime.strptime("%Y-%m-%d", "2020-01-01") == 1577836800); -assert(Datetime.strptime("%Y-%b-%d", "2020-Jan-01") == 1577836800); -assert(Datetime.strptime("%Y-%B-%d", "2020-January-01") == 1577836800); + assert(Datetime.strptime("%Y-%m-%d", "2020-1-1") == 1577836800); + assert(Datetime.strptime("%Y-%m-%d", "2020-01-1") == 1577836800); + assert(Datetime.strptime("%Y-%b-%d", "2020-Jan-1") == 1577836800); + assert(Datetime.strptime("%Y-%B-%d", "2020-January-1") == 1577836800); + assert(Datetime.strptime("%Y-%m-%d", "2020-1-01") == 1577836800); + assert(Datetime.strptime("%Y-%m-%d", "2020-01-01") == 1577836800); + assert(Datetime.strptime("%Y-%b-%d", "2020-Jan-01") == 1577836800); + assert(Datetime.strptime("%Y-%B-%d", "2020-January-01") == 1577836800); -// 1577836800 is 1/1/2020 at 12:00 am -assert(Datetime.strptime("%y", "20") == 1577836800); -assert(Datetime.strptime("%y-%m", "20-1") == 1577836800); -assert(Datetime.strptime("%y-%m", "20-01") == 1577836800); -assert(Datetime.strptime("%y-%b", "20-Jan") == 1577836800); -assert(Datetime.strptime("%y-%B", "20-January") == 1577836800); + // 1577836800 is 1/1/2020 at 12:00 am + assert(Datetime.strptime("%y", "20") == 1577836800); + assert(Datetime.strptime("%y-%m", "20-1") == 1577836800); + assert(Datetime.strptime("%y-%m", "20-01") == 1577836800); + assert(Datetime.strptime("%y-%b", "20-Jan") == 1577836800); + assert(Datetime.strptime("%y-%B", "20-January") == 1577836800); -assert(Datetime.strptime("%y-%d", "20-1") == 1577836800); -assert(Datetime.strptime("%y-%d", "20-01") == 1577836800); + assert(Datetime.strptime("%y-%d", "20-1") == 1577836800); + assert(Datetime.strptime("%y-%d", "20-01") == 1577836800); -assert(Datetime.strptime("%y-%m-%d", "20-1-1") == 1577836800); -assert(Datetime.strptime("%y-%m-%d", "20-01-1") == 1577836800); -assert(Datetime.strptime("%y-%b-%d", "20-Jan-1") == 1577836800); -assert(Datetime.strptime("%y-%B-%d", "20-January-1") == 1577836800); -assert(Datetime.strptime("%y-%m-%d", "20-1-01") == 1577836800); -assert(Datetime.strptime("%y-%m-%d", "20-01-01") == 1577836800); -assert(Datetime.strptime("%y-%b-%d", "20-Jan-01") == 1577836800); -assert(Datetime.strptime("%y-%B-%d", "20-January-01") == 1577836800); \ No newline at end of file + assert(Datetime.strptime("%y-%m-%d", "20-1-1") == 1577836800); + assert(Datetime.strptime("%y-%m-%d", "20-01-1") == 1577836800); + assert(Datetime.strptime("%y-%b-%d", "20-Jan-1") == 1577836800); + assert(Datetime.strptime("%y-%B-%d", "20-January-1") == 1577836800); + assert(Datetime.strptime("%y-%m-%d", "20-1-01") == 1577836800); + assert(Datetime.strptime("%y-%m-%d", "20-01-01") == 1577836800); + assert(Datetime.strptime("%y-%b-%d", "20-Jan-01") == 1577836800); + assert(Datetime.strptime("%y-%B-%d", "20-January-01") == 1577836800); +} \ No newline at end of file diff --git a/tests/files/seek.du b/tests/files/seek.du index 2d79f916..9fe97337 100644 --- a/tests/files/seek.du +++ b/tests/files/seek.du @@ -6,13 +6,13 @@ var contents; -with("tests/files/read.txt", "r") { +with("tests/files/read.txt", "rb") { contents = file.read(); } assert(type(contents) == "string"); -with("tests/files/read.txt", "r") { +with("tests/files/read.txt", "rb") { var fileContents = file.read(); file.seek(0); assert(file.read() == fileContents); diff --git a/tests/system/mkdir.du b/tests/system/mkdir.du index d2cb9943..6415d53e 100644 --- a/tests/system/mkdir.du +++ b/tests/system/mkdir.du @@ -32,6 +32,10 @@ with(sys_test_dir, "w") { } assert(System.rmdir(sys_test_dir) == -1); -assert(System.errno == C.ENOTDIR); -assert(System.strerror() == "Not a directory"); +assert(System.errno == C.ENOTDIR or System.errno == C.EINVAL); +if (System.errno == C.ENOTDIR) { + assert(System.strerror() == "Not a directory"); +} else if (System.errno == C.EINVAL) { + assert(System.strerror() == "Invalid argument"); +} assert(System.remove(sys_test_dir) == 0); diff --git a/tests/system/process.du b/tests/system/process.du index 9b42c97e..09945013 100644 --- a/tests/system/process.du +++ b/tests/system/process.du @@ -7,10 +7,12 @@ * about the running process. */ -assert(type(System.getpid()) == "number"); -assert(type(System.getppid()) == "number"); -assert(type(System.getuid()) == "number"); -assert(type(System.geteuid()) == "number"); -assert(type(System.getgid()) == "number"); -assert(type(System.getegid()) == "number"); +if (System.platform != "windows") { + assert(type(System.getpid()) == "number"); + assert(type(System.getppid()) == "number"); + assert(type(System.getuid()) == "number"); + assert(type(System.geteuid()) == "number"); + assert(type(System.getgid()) == "number"); + assert(type(System.getegid()) == "number"); +} diff --git a/tests/system/remove.du b/tests/system/remove.du index 41f56c56..0fceb468 100644 --- a/tests/system/remove.du +++ b/tests/system/remove.du @@ -32,7 +32,11 @@ if (System.platform == 'darwin') { assert(System.remove(sys_test_remove) == 0); assert(System.mkdir(sys_test_remove) == 0); assert(System.remove(sys_test_remove) == -1); - assert(System.errno == C.EISDIR); - assert(System.strerror() == "Is a directory"); + assert(System.errno == C.EISDIR or System.errno == C.EACCES); + if (System.errno == C.EISDIR) { + assert(System.strerror() == "Is a directory"); + } else if (System.errno == C.EACCES) { + assert(System.strerror() == "Permission denied"); + } assert(System.rmdir(sys_test_remove) == 0); } diff --git a/tests/system/setCWD.du b/tests/system/setCWD.du index 14b376b4..10da8a8d 100644 --- a/tests/system/setCWD.du +++ b/tests/system/setCWD.du @@ -11,7 +11,11 @@ assert(cwd != nil); assert(type(cwd) == "string"); assert(cwd.len() > 0); assert(System.setCWD("/") == 0); -assert(System.getCWD() == "/"); +if (System.platform == "windows") { + assert(System.getCWD() == "C:\\"); +} else { + assert(System.getCWD() == "/"); +} assert(System.setCWD(cwd) == 0); assert(System.getCWD() == cwd); assert(System.setCWD("some/directory/that/doesnt/exist") == -1); From 6ba912aede5c5260fdffbd516c971b2170659753 Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sat, 3 Oct 2020 20:11:39 -0700 Subject: [PATCH 19/61] Add Random.random() method --- c/optionals/optionals.c | 1 + c/optionals/optionals.h | 1 + c/optionals/random.c | 29 +++++++++++++++++++++++++++++ c/optionals/random.h | 11 +++++++++++ tests/random/import.du | 9 +++++++++ tests/random/random.du | 24 ++++++++++++++++++++++++ tests/random/range.du | 0 tests/random/select.du | 0 8 files changed, 75 insertions(+) create mode 100644 c/optionals/random.c create mode 100644 c/optionals/random.h create mode 100644 tests/random/import.du create mode 100644 tests/random/random.du create mode 100644 tests/random/range.du create mode 100644 tests/random/select.du diff --git a/c/optionals/optionals.c b/c/optionals/optionals.c index f7e0f5a5..235e8917 100644 --- a/c/optionals/optionals.c +++ b/c/optionals/optionals.c @@ -7,6 +7,7 @@ BuiltinModules modules[] = { {"Path", &createPathClass}, {"Datetime", &createDatetimeClass}, {"Socket", &createSocketClass}, + {"Random", &createRandomClass}, #ifndef DISABLE_HTTP {"HTTP", &createHTTPClass}, #endif diff --git a/c/optionals/optionals.h b/c/optionals/optionals.h index e4272bad..68d48002 100644 --- a/c/optionals/optionals.h +++ b/c/optionals/optionals.h @@ -11,6 +11,7 @@ #include "c.h" #include "datetime.h" #include "socket.h" +#include "random.h" #define GET_SELF_CLASS \ AS_MODULE(args[-1]) diff --git a/c/optionals/random.c b/c/optionals/random.c new file mode 100644 index 00000000..7e4380b8 --- /dev/null +++ b/c/optionals/random.c @@ -0,0 +1,29 @@ +#include "random.h" + +static Value randomRandom(VM * vm, int argCount, Value *args) { + args = args; // FIXME: Can't get -Werror to surpress not using args + if (argCount > 0) { + runtimeError(vm, "random() takes 0 arguments (%d given)", argCount); + return EMPTY_VAL; + } + return NUMBER_VAL(rand() % 2); +} + + +ObjModule *createRandomClass(VM *vm) { + ObjString *name = copyString(vm, "Random", 6); + push(vm, OBJ_VAL(name)); + ObjModule *module = newModule(vm, name); + push(vm, OBJ_VAL(module)); + + /** + * Define Random methods + */ + defineNative(vm, &module->values, "random", randomRandom); + // TODO: Define randomRange and randomSelect + + pop(vm); + pop(vm); + + return module; +} \ No newline at end of file diff --git a/c/optionals/random.h b/c/optionals/random.h new file mode 100644 index 00000000..a85d6f09 --- /dev/null +++ b/c/optionals/random.h @@ -0,0 +1,11 @@ +#ifndef dictu_random_h +#define dictu_random_h + +#include + +#include "optionals.h" +#include "../vm.h" + +ObjModule *createRandomClass(VM *vm); + +#endif //dictu_random_h diff --git a/tests/random/import.du b/tests/random/import.du new file mode 100644 index 00000000..d479948d --- /dev/null +++ b/tests/random/import.du @@ -0,0 +1,9 @@ +/** + * import.du + * + * General import file for all the methods for Random + */ + +import "tests/random/random.du"; +import "tests/random/select.du"; +import "tests/random/range.du"; \ No newline at end of file diff --git a/tests/random/random.du b/tests/random/random.du new file mode 100644 index 00000000..660aa905 --- /dev/null +++ b/tests/random/random.du @@ -0,0 +1,24 @@ +/** + * random.du + * + * Testing the Random.random() method + * + */ + +import Random; + +var histogram = {0: 0, 1: 0}; +var num_randomizations = 100; +var percent_error = 0.05; +for (var i = 0; i < num_randomizations; ++i) { + histogram[Random.random()] += 1; +} + +var exp_percent = 0.5; +var min_percent = exp_percent - percent_error; +var max_percent = exp_percent + percent_error; +for (var i = 0; i < histogram.len(); ++i) { + var percent_of_i = histogram[i] / num_randomizations; + assert(min_percent <= percent_of_i); + assert(percent_of_i <= max_percent); +} diff --git a/tests/random/range.du b/tests/random/range.du new file mode 100644 index 00000000..e69de29b diff --git a/tests/random/select.du b/tests/random/select.du new file mode 100644 index 00000000..e69de29b From 418212e61f870c9b96d0b6aeced8ee098e48e1d3 Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sat, 3 Oct 2020 20:46:00 -0700 Subject: [PATCH 20/61] Implement Random.range() --- c/optionals/random.c | 25 +++++++++++++++++++++++-- tests/random/random.du | 6 +++--- tests/random/range.du | 26 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/c/optionals/random.c b/c/optionals/random.c index 7e4380b8..b2f7acea 100644 --- a/c/optionals/random.c +++ b/c/optionals/random.c @@ -1,6 +1,6 @@ #include "random.h" -static Value randomRandom(VM * vm, int argCount, Value *args) { +static Value randomRandom(VM *vm, int argCount, Value *args) { args = args; // FIXME: Can't get -Werror to surpress not using args if (argCount > 0) { runtimeError(vm, "random() takes 0 arguments (%d given)", argCount); @@ -9,6 +9,26 @@ static Value randomRandom(VM * vm, int argCount, Value *args) { return NUMBER_VAL(rand() % 2); } +static Value randomRange(VM *vm, int argCount, Value *args) { + if (argCount != 2) { + runtimeError(vm, "range() takes 2 arguments (%0d given)", argCount); + return EMPTY_VAL; + } + + if (!IS_NUMBER(args[0]) || !IS_NUMBER(args[1])) { + runtimeError(vm, "range() arguments must be numbers"); + return EMPTY_VAL; + } + + int upper = AS_NUMBER(args[1]); + int lower = AS_NUMBER(args[0]); + int random_val = (rand() % (upper - lower + 1)) + lower; + return NUMBER_VAL(random_val); +} + +// static Value randomSelect(VM *vm, int argCount, Value *args) { + +// } ObjModule *createRandomClass(VM *vm) { ObjString *name = copyString(vm, "Random", 6); @@ -20,7 +40,8 @@ ObjModule *createRandomClass(VM *vm) { * Define Random methods */ defineNative(vm, &module->values, "random", randomRandom); - // TODO: Define randomRange and randomSelect + defineNative(vm, &module->values, "range", randomRange); + // defineNative(vm, &module->values, "random", randomSelect); pop(vm); pop(vm); diff --git a/tests/random/random.du b/tests/random/random.du index 660aa905..c4080993 100644 --- a/tests/random/random.du +++ b/tests/random/random.du @@ -9,14 +9,14 @@ import Random; var histogram = {0: 0, 1: 0}; var num_randomizations = 100; -var percent_error = 0.05; +var percent_error_threshold = 0.05; for (var i = 0; i < num_randomizations; ++i) { histogram[Random.random()] += 1; } var exp_percent = 0.5; -var min_percent = exp_percent - percent_error; -var max_percent = exp_percent + percent_error; +var min_percent = exp_percent - percent_error_threshold; +var max_percent = exp_percent + percent_error_threshold; for (var i = 0; i < histogram.len(); ++i) { var percent_of_i = histogram[i] / num_randomizations; assert(min_percent <= percent_of_i); diff --git a/tests/random/range.du b/tests/random/range.du index e69de29b..c8ba45af 100644 --- a/tests/random/range.du +++ b/tests/random/range.du @@ -0,0 +1,26 @@ +/** + * range.du + * + * Testing the Random.range() method + * + */ + +import Random; + +var histogram = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}; +var num_randomizations = 500; +var percent_error_threshold = 0.05; + +for (var i = 0; i < num_randomizations; ++i) { + histogram[Random.range(1, 5)] += 1; +} + +var exp_percent = 0.2; +var min_percent = exp_percent - percent_error_threshold; +var max_percent = exp_percent + percent_error_threshold; +for (var i = 0; i < histogram.len(); ++i) { + var key = histogram.keys()[i]; + var percent_of_key = histogram[key] / num_randomizations; + assert(min_percent <= percent_of_key); + assert(percent_of_key <= max_percent); +} From 96207c0b32d02134590e905a876dd1b2a6aad3ba Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sat, 3 Oct 2020 20:58:52 -0700 Subject: [PATCH 21/61] Implement Random.select() --- c/optionals/random.c | 31 +++++++++++++++++++++++++++---- tests/random/select.du | 26 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/c/optionals/random.c b/c/optionals/random.c index b2f7acea..0d7caba5 100644 --- a/c/optionals/random.c +++ b/c/optionals/random.c @@ -1,7 +1,7 @@ #include "random.h" static Value randomRandom(VM *vm, int argCount, Value *args) { - args = args; // FIXME: Can't get -Werror to surpress not using args + UNUSED(args); if (argCount > 0) { runtimeError(vm, "random() takes 0 arguments (%d given)", argCount); return EMPTY_VAL; @@ -26,9 +26,32 @@ static Value randomRange(VM *vm, int argCount, Value *args) { return NUMBER_VAL(random_val); } -// static Value randomSelect(VM *vm, int argCount, Value *args) { +static Value randomSelect(VM *vm, int argCount, Value *args) { + if (argCount == 0) { + runtimeError(vm, "select() takes one argument (%0d provided)", argCount); + return EMPTY_VAL; + } + + if (!IS_LIST(args[0])) { + runtimeError(vm, "select() argument must be a list"); + return EMPTY_VAL; + } -// } + ObjList *list = AS_LIST(args[0]); + argCount = list->values.count; + args = list->values.values; + + for (int i = 0; i < argCount; ++i) { + Value value = args[i]; + if (!IS_NUMBER(value)) { + runtimeError(vm, "A non-number value passed to select()"); + return EMPTY_VAL; + } + } + + int index = rand() % argCount; + return args[index]; +} ObjModule *createRandomClass(VM *vm) { ObjString *name = copyString(vm, "Random", 6); @@ -41,7 +64,7 @@ ObjModule *createRandomClass(VM *vm) { */ defineNative(vm, &module->values, "random", randomRandom); defineNative(vm, &module->values, "range", randomRange); - // defineNative(vm, &module->values, "random", randomSelect); + defineNative(vm, &module->values, "select", randomSelect); pop(vm); pop(vm); diff --git a/tests/random/select.du b/tests/random/select.du index e69de29b..5628d064 100644 --- a/tests/random/select.du +++ b/tests/random/select.du @@ -0,0 +1,26 @@ +/** + * select.du + * + * Testing the Random.select() method + * + */ + +import Random; + +var histogram = {1: 0, 3: 0, 5: 0, 7: 0, 9: 0}; +var num_randomizations = 500; +var percent_error_threshold = 0.05; + +for (var i = 0; i < num_randomizations; ++i) { + histogram[Random.select([1, 3, 5, 7, 9])] += 1; +} + +var exp_percent = 0.2; +var min_percent = exp_percent - percent_error_threshold; +var max_percent = exp_percent + percent_error_threshold; +for (var i = 0; i < histogram.len(); ++i) { + var key = histogram.keys()[i]; + var percent_of_key = histogram[key] / num_randomizations; + assert(min_percent <= percent_of_key); + assert(percent_of_key <= max_percent); +} From 034ed5946109a1b2f9161d94d0b44cbbcb814ef3 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:17:44 -0700 Subject: [PATCH 22/61] Add documentation to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index d7af061a..7e6055ef 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ compile_commands.json venv/ cmake-build-debug/CMakeFiles/clion-log.txt + +docs/.jekyll-cache/ +docs/_site/ \ No newline at end of file From 04ab7e34caff64c2233590899f1fbfc10f6bd460 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:18:28 -0700 Subject: [PATCH 23/61] Tidy config file --- docs/_config.yml | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index 1cbfd6a6..e0ce9f2d 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,40 +1,29 @@ -# Welcome to Jekyll! -# -# This config file is meant for settings that affect your whole blog, values -# which you are expected to set up once and rarely edit after that. If you find -# yourself editing this file very often, consider using Jekyll's data files -# feature for the data you need to update frequently. -# -# For technical reasons, this file is *NOT* reloaded automatically when you use -# 'bundle exec jekyll serve'. If you change this file, please restart the server process. - -# Site settings -# These are used to personalize your new site. If you look in the HTML files, -# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. -# You can create any custom variable you would like, and they will be accessible -# in the templates via {{ site.myvariable }}. -# Enable or disable the site search +title: Dictu +description: >- + Dictu is a very simple dynamically typed programming language built upon the craftinginterpreters tutorial. + +color_scheme: "dictu" # Custom theme +logo: "/assets/images/dictu-logo/dictu-wordmark.svg" + +version: "0.10.0" +github_username: dictu-lang search_enabled: true + url: "https://dictu-lang.com" +# theme: "just-the-docs" +footer_content: "This site uses Just The Docs, with modifications." ga_tracking: "UA-109828853-2" -# Aux links for the upper right navigation aux_links: - "View Dictu on GitHub": - - "//github.com/Jason2605/dictu" + "Contribute on GitHub": + - "//github.com/dictu-lang/Dictu" -# Color scheme currently only supports "dark" or nil (default) -color_scheme: nil +# Don't touch anything beyond this point permalink: pretty exclude: ["node_modules/", "*.gemspec", "*.gem", "Gemfile", "Gemfile.lock", "package.json", "package-lock.json", "script/", "LICENSE.txt", "lib/", "bin/", "README.md", "Rakefile"] -title: Dictu -description: >- # this means to ignore newlines until "baseurl:" - Dictu is a very simple dynamically typed programming language built upon the craftinginterpreters tutorial. -github_username: Jason2605 - # Build settings markdown: kramdown remote_theme: pmarsceill/just-the-docs @@ -42,8 +31,6 @@ plugins: - jekyll-feed - jekyll-sitemap -version: "0.10.0" - # Exclude from processing. # The following items will not be processed, by default. Create a custom list # to override the default setting. From d8162e2e2574ac8e0cef214619d3b0b83fb1ba92 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:20:55 -0700 Subject: [PATCH 24/61] Use Just the Docs locally To make customizations to Just the Docs, I'm pretty sure that it cannot be used as a remote theme. It is also necessary to run Jekyll locally. --- docs/_includes/css/custom.scss.liquid | 1 + docs/_includes/css/just-the-docs.scss.liquid | 7 + docs/_includes/fix_linenos.html | 65 +++ docs/_includes/head.html | 79 +-- docs/_includes/head_custom.html | 0 docs/_includes/js/custom.js | 0 docs/_includes/nav.html | 100 ++++ docs/_includes/title.html | 5 + docs/_includes/vendor/anchor_headings.html | 144 ++++++ docs/_layouts/about.html | 5 + docs/_layouts/default.html | 184 +++++++ docs/_layouts/home.html | 5 + docs/_layouts/page.html | 5 + docs/_layouts/post.html | 5 + docs/_layouts/table_wrappers.html | 7 + docs/_layouts/vendor/compress.html | 10 + docs/_sass/base.scss | 108 ++++ docs/_sass/buttons.scss | 118 +++++ docs/_sass/code.scss | 334 +++++++++++++ docs/_sass/color_schemes/dark.scss | 17 + docs/_sass/color_schemes/light.scss | 0 docs/_sass/content.scss | 199 ++++++++ docs/_sass/labels.scss | 37 ++ docs/_sass/layout.scss | 205 ++++++++ docs/_sass/modules.scss | 20 + docs/_sass/navigation.scss | 219 ++++++++ docs/_sass/print.scss | 40 ++ docs/_sass/search.scss | 323 ++++++++++++ docs/_sass/support/_functions.scss | 9 + docs/_sass/support/_variables.scss | 153 ++++++ docs/_sass/support/mixins/_buttons.scss | 27 + docs/_sass/support/mixins/_layout.scss | 34 ++ docs/_sass/support/mixins/_typography.scss | 84 ++++ docs/_sass/support/mixins/mixins.scss | 3 + docs/_sass/support/support.scss | 3 + docs/_sass/tables.scss | 58 +++ docs/_sass/typography.scss | 64 +++ docs/_sass/utilities/_colors.scss | 239 +++++++++ docs/_sass/utilities/_layout.scss | 95 ++++ docs/_sass/utilities/_lists.scss | 17 + docs/_sass/utilities/_spacing.scss | 165 ++++++ docs/_sass/utilities/_typography.scss | 91 ++++ docs/_sass/utilities/utilities.scss | 5 + docs/_sass/vendor/normalize.scss/README.md | 78 +++ .../vendor/normalize.scss/normalize.scss | 427 ++++++++++++++++ docs/_sass/vendor/normalize.scss/package.json | 70 +++ docs/assets/css/just-the-docs-dark.scss | 3 + docs/assets/css/just-the-docs-default.scss | 8 + docs/assets/css/just-the-docs-light.scss | 3 + docs/assets/images/search.svg | 1 + docs/assets/js/just-the-docs.js | 471 ++++++++++++++++++ docs/assets/js/vendor/lunr.min.js | 6 + docs/bin/just-the-docs | 16 + 53 files changed, 4320 insertions(+), 52 deletions(-) create mode 100755 docs/_includes/css/custom.scss.liquid create mode 100755 docs/_includes/css/just-the-docs.scss.liquid create mode 100755 docs/_includes/fix_linenos.html mode change 100644 => 100755 docs/_includes/head.html create mode 100755 docs/_includes/head_custom.html create mode 100755 docs/_includes/js/custom.js create mode 100755 docs/_includes/nav.html create mode 100755 docs/_includes/title.html create mode 100755 docs/_includes/vendor/anchor_headings.html create mode 100755 docs/_layouts/about.html create mode 100755 docs/_layouts/default.html create mode 100755 docs/_layouts/home.html create mode 100755 docs/_layouts/page.html create mode 100755 docs/_layouts/post.html create mode 100755 docs/_layouts/table_wrappers.html create mode 100755 docs/_layouts/vendor/compress.html create mode 100755 docs/_sass/base.scss create mode 100755 docs/_sass/buttons.scss create mode 100755 docs/_sass/code.scss create mode 100755 docs/_sass/color_schemes/dark.scss create mode 100755 docs/_sass/color_schemes/light.scss create mode 100755 docs/_sass/content.scss create mode 100755 docs/_sass/labels.scss create mode 100755 docs/_sass/layout.scss create mode 100755 docs/_sass/modules.scss create mode 100755 docs/_sass/navigation.scss create mode 100755 docs/_sass/print.scss create mode 100755 docs/_sass/search.scss create mode 100755 docs/_sass/support/_functions.scss create mode 100755 docs/_sass/support/_variables.scss create mode 100755 docs/_sass/support/mixins/_buttons.scss create mode 100755 docs/_sass/support/mixins/_layout.scss create mode 100755 docs/_sass/support/mixins/_typography.scss create mode 100755 docs/_sass/support/mixins/mixins.scss create mode 100755 docs/_sass/support/support.scss create mode 100755 docs/_sass/tables.scss create mode 100755 docs/_sass/typography.scss create mode 100755 docs/_sass/utilities/_colors.scss create mode 100755 docs/_sass/utilities/_layout.scss create mode 100755 docs/_sass/utilities/_lists.scss create mode 100755 docs/_sass/utilities/_spacing.scss create mode 100755 docs/_sass/utilities/_typography.scss create mode 100755 docs/_sass/utilities/utilities.scss create mode 100755 docs/_sass/vendor/normalize.scss/README.md create mode 100755 docs/_sass/vendor/normalize.scss/normalize.scss create mode 100755 docs/_sass/vendor/normalize.scss/package.json create mode 100755 docs/assets/css/just-the-docs-dark.scss create mode 100755 docs/assets/css/just-the-docs-default.scss create mode 100755 docs/assets/css/just-the-docs-light.scss create mode 100755 docs/assets/images/search.svg create mode 100755 docs/assets/js/just-the-docs.js create mode 100755 docs/assets/js/vendor/lunr.min.js create mode 100755 docs/bin/just-the-docs diff --git a/docs/_includes/css/custom.scss.liquid b/docs/_includes/css/custom.scss.liquid new file mode 100755 index 00000000..2ad1576e --- /dev/null +++ b/docs/_includes/css/custom.scss.liquid @@ -0,0 +1 @@ +@import "./custom/custom"; diff --git a/docs/_includes/css/just-the-docs.scss.liquid b/docs/_includes/css/just-the-docs.scss.liquid new file mode 100755 index 00000000..495cd6dd --- /dev/null +++ b/docs/_includes/css/just-the-docs.scss.liquid @@ -0,0 +1,7 @@ +{% if site.logo %} +$logo: "{{ site.logo | absolute_url }}"; +{% endif %} +@import "./support/support"; +@import "./color_schemes/{{ include.color_scheme }}"; +@import "./modules"; +{% include css/custom.scss.liquid %} diff --git a/docs/_includes/fix_linenos.html b/docs/_includes/fix_linenos.html new file mode 100755 index 00000000..6243fb09 --- /dev/null +++ b/docs/_includes/fix_linenos.html @@ -0,0 +1,65 @@ +{%- comment -%} +This file can be used to fix the HTML produced by Jekyll for highlighted +code with line numbers. + +It works with `{% highlight some_language linenos %}...{% endhighlight %}` +and with the Kramdown option to add line numbers to fenced code. + +The implementation was derived from the workaround provided by +Dmitry Hrabrov (DeXP) at +https://github.com/penibelst/jekyll-compress-html/issues/71#issuecomment-188144901 + +EXPLANATION + +The HTML produced by Rouge highlighting with lie numbers is of the form +`code table`. Jekyll (<= 4.1.1) always wraps the highlighted HTML +with `pre`. This wrapping is not only unnecessary, but also transforms +the conforming HTML produced by Rouge to non-conforming HTML, which +results in HTML validation error reports. + +The fix removes the outer `pre` tags whenever they contain the pattern +``. + +Apart from avoiding HTML validation errors, the fix allows the use of +the [Jekyll layout for compressing HTML](http://jch.penibelst.de), +which relies on `pre` tags not being nested, according to +https://github.com/penibelst/jekyll-compress-html/issues/71#issuecomment-172069842 + +USAGE + +(Any names can be used for `some_var` and `some_language`.) + +{% capture some_var %} +{% highlight some_language linenos %} +Some code +{% endhighlight %} +{% endcapture %} +{% include fix_linenos.html code=some_var %} + +For code fences: + +{% capture some_var %} +```some_language +Some code +``` +{% endcapture %} +{% assign some_var = some_var | markdownify %} +{% include fix_linenos.html code=some_var %} + +CAVEATS + +The above does not work when `Some code` happens to contain the matched string +`
`. + +The use of this file overwrites the variable `fix_linenos_code` with `nil`. + +{%- endcomment -%} + +{% assign fix_linenos_code = include.code %} +{% if fix_linenos_code contains '
' %} + {% assign fix_linenos_code = fix_linenos_code | replace: '
', '
' %}
+  {% assign fix_linenos_code = fix_linenos_code | replace: "
", "" %} +{% endif %} +{{ fix_linenos_code }} +{% assign fix_linenos_code = nil %} diff --git a/docs/_includes/head.html b/docs/_includes/head.html old mode 100644 new mode 100755 index 74983859..149e53d1 --- a/docs/_includes/head.html +++ b/docs/_includes/head.html @@ -1,54 +1,29 @@ - - - - - - - - - - - - {{ page.title }} - {{ site.title }} - - - - - {% if site.ga_tracking != nil %} - - - - {% endif %} - - {% if site.search_enabled != nil %} - - {% endif %} - - - + + + + + + + {{ page.title }} - {{ site.title }} + + + {% if site.ga_tracking != nil %} + + + + {% endif %} + + {% if site.search_enabled != nil %} + + {% endif %} + + + \ No newline at end of file diff --git a/docs/_includes/head_custom.html b/docs/_includes/head_custom.html new file mode 100755 index 00000000..e69de29b diff --git a/docs/_includes/js/custom.js b/docs/_includes/js/custom.js new file mode 100755 index 00000000..e69de29b diff --git a/docs/_includes/nav.html b/docs/_includes/nav.html new file mode 100755 index 00000000..976dbbd7 --- /dev/null +++ b/docs/_includes/nav.html @@ -0,0 +1,100 @@ + diff --git a/docs/_includes/title.html b/docs/_includes/title.html new file mode 100755 index 00000000..8bd3fa83 --- /dev/null +++ b/docs/_includes/title.html @@ -0,0 +1,5 @@ +{% if site.logo %} + +{% else %} + {{ site.title }} +{% endif %} diff --git a/docs/_includes/vendor/anchor_headings.html b/docs/_includes/vendor/anchor_headings.html new file mode 100755 index 00000000..e9ca8626 --- /dev/null +++ b/docs/_includes/vendor/anchor_headings.html @@ -0,0 +1,144 @@ +{% capture headingsWorkspace %} + {% comment %} + Copyright (c) 2018 Vladimir "allejo" Jimenez + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + {% endcomment %} + {% comment %} + Version 1.0.7 + https://github.com/allejo/jekyll-anchor-headings + + "Be the pull request you wish to see in the world." ~Ben Balter + + Usage: + {% include anchor_headings.html html=content anchorBody="#" %} + + Parameters: + * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll + + Optional Parameters: + * beforeHeading (bool) : false - Set to true if the anchor should be placed _before_ the heading's content + * anchorAttrs (string) : '' - Any custom HTML attributes that will be added to the `` tag; you may NOT use `href`, `class` or `title`; + the `%heading%` and `%html_id%` placeholders are available + * anchorBody (string) : '' - The content that will be placed inside the anchor; the `%heading%` placeholder is available + * anchorClass (string) : '' - The class(es) that will be used for each anchor. Separate multiple classes with a space + * anchorTitle (string) : '' - The `title` attribute that will be used for anchors + * h_min (int) : 1 - The minimum header level to build an anchor for; any header lower than this value will be ignored + * h_max (int) : 6 - The maximum header level to build an anchor for; any header greater than this value will be ignored + * bodyPrefix (string) : '' - Anything that should be inserted inside of the heading tag _before_ its anchor and content + * bodySuffix (string) : '' - Anything that should be inserted inside of the heading tag _after_ its anchor and content + + Output: + The original HTML with the addition of anchors inside of all of the h1-h6 headings. + {% endcomment %} + + {% assign minHeader = include.h_min | default: 1 %} + {% assign maxHeader = include.h_max | default: 6 %} + {% assign beforeHeading = include.beforeHeading %} + {% assign nodes = include.html | split: ' + {% if headerLevel == 0 %} + + {% assign firstChunk = node | split: '>' | first %} + + + {% unless firstChunk contains '<' %} + {% capture node %}{% endcapture %} + {% assign _workspace = node | split: _closingTag %} + {% assign _idWorkspace = _workspace[0] | split: 'id="' %} + {% assign _idWorkspace = _idWorkspace[1] | split: '"' %} + {% assign html_id = _idWorkspace[0] %} + + {% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %} + {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %} + + + {% capture anchor %}{% endcapture %} + + {% if html_id and headerLevel >= minHeader and headerLevel <= maxHeader %} + {% capture anchor %}href="#{{ html_id }}"{% endcapture %} + + {% if include.anchorClass %} + {% capture anchor %}{{ anchor }} class="{{ include.anchorClass }}"{% endcapture %} + {% endif %} + + {% if include.anchorTitle %} + {% capture anchor %}{{ anchor }} title="{{ include.anchorTitle | replace: '%heading%', header }}"{% endcapture %} + {% endif %} + + {% if include.anchorAttrs %} + {% capture anchor %}{{ anchor }} {{ include.anchorAttrs | replace: '%heading%', header | replace: '%html_id%', html_id }}{% endcapture %} + {% endif %} + + {% capture anchor %}{{ include.anchorBody | replace: '%heading%', header | default: '' }}{% endcapture %} + + + {% if beforeHeading %} + {% capture anchor %}{{ anchor }} {% endcapture %} + {% else %} + {% capture anchor %} {{ anchor }}{% endcapture %} + {% endif %} + {% endif %} + + {% capture new_heading %} + + {% endcapture %} + + + {% assign chunkCount = _workspace | size %} + {% if chunkCount > 1 %} + {% capture new_heading %}{{ new_heading }}{{ _workspace | last }}{% endcapture %} + {% endif %} + + {% capture edited_headings %}{{ edited_headings }}{{ new_heading }}{% endcapture %} + {% endfor %} +{% endcapture %}{% assign headingsWorkspace = '' %}{{ edited_headings | strip }} diff --git a/docs/_layouts/about.html b/docs/_layouts/about.html new file mode 100755 index 00000000..5e711268 --- /dev/null +++ b/docs/_layouts/about.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +{{ content }} diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100755 index 00000000..442d44d7 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,184 @@ +--- +layout: table_wrappers +--- + + + + +{% include head.html %} + + + + Link + + + + + + Search + + + + + + Menu + + + + + + Expand + + + + + + Document + + + + + + + +
+
+ {% if site.search_enabled != false %} + + {% endif %} + {% if site.aux_links %} + + {% endif %} +
+
+ {% unless page.url == "/" %} + {% if page.parent %} + + {% endif %} + {% endunless %} +
+ {% if site.heading_anchors != false %} + {% include vendor/anchor_headings.html html=content beforeHeading="true" anchorBody="" anchorClass="anchor-heading" anchorAttrs="aria-labelledby=\"%html_id%\"" %} + {% else %} + {{ content }} + {% endif %} + + {% if page.has_children == true and page.has_toc != false %} +
+

Table of contents

+
    + {%- assign children_list = pages_list | where: "parent", page.title | where: "grand_parent", page.parent -%} + {% for child in children_list %} +
  • + {{ child.title }}{% if child.summary %} - {{ child.summary }}{% endif %} +
  • + {% endfor %} +
+ {% endif %} + + {% if site.footer_content != nil or site.last_edit_timestamp or site.gh_edit_link %} +
+
+ {% if site.back_to_top %} +

{{ site.back_to_top_text }}

+ {% endif %} + {% if site.footer_content != nil %} +

{{ site.footer_content }}

+ {% endif %} + + {% if site.last_edit_timestamp or site.gh_edit_link %} +
+ {% if site.last_edit_timestamp and site.last_edit_time_format and page.last_modified_date %} +

+ Page last modified: {{ page.last_modified_date | date: site.last_edit_time_format }}. +

+ {% endif %} + {% if + site.gh_edit_link and + site.gh_edit_link_text and + site.gh_edit_repository and + site.gh_edit_branch and + site.gh_edit_view_mode + %} +

+ {{ site.gh_edit_link_text }} +

+ {% endif %} +
+ {% endif %} +
+ {% endif %} + +
+
+ + {% if site.search_enabled != false %} + {% if site.search.button %} + + + + {% endif %} + +
+ {% endif %} +
+ + diff --git a/docs/_layouts/home.html b/docs/_layouts/home.html new file mode 100755 index 00000000..5e711268 --- /dev/null +++ b/docs/_layouts/home.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +{{ content }} diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html new file mode 100755 index 00000000..5e711268 --- /dev/null +++ b/docs/_layouts/page.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +{{ content }} diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html new file mode 100755 index 00000000..5e711268 --- /dev/null +++ b/docs/_layouts/post.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +{{ content }} diff --git a/docs/_layouts/table_wrappers.html b/docs/_layouts/table_wrappers.html new file mode 100755 index 00000000..3f8f226a --- /dev/null +++ b/docs/_layouts/table_wrappers.html @@ -0,0 +1,7 @@ +--- +layout: vendor/compress +--- + +{% assign content_ = content | replace: '', '
' %} +{{ content_ }} diff --git a/docs/_layouts/vendor/compress.html b/docs/_layouts/vendor/compress.html new file mode 100755 index 00000000..bb34487d --- /dev/null +++ b/docs/_layouts/vendor/compress.html @@ -0,0 +1,10 @@ +--- +# Jekyll layout that compresses HTML +# v3.1.0 +# http://jch.penibelst.de/ +# © 2014–2015 Anatol Broder +# MIT License +--- + +{% capture _LINE_FEED %} +{% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "" %}{% endif %}{% unless _pre_before contains "" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " ;; ;" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %}
Step Bytes
raw {{ content | size }}{% if _profile_endings %}
endings {{ _profile_endings }}{% endif %}{% if _profile_startings %}
startings {{ _profile_startings }}{% endif %}{% if _profile_comments %}
comments {{ _profile_comments }}{% endif %}{% if _profile_collapse %}
collapse {{ _profile_collapse }}{% endif %}{% if _profile_clippings %}
clippings {{ _profile_clippings }}{% endif %}
{% endif %}{% endif %} diff --git a/docs/_sass/base.scss b/docs/_sass/base.scss new file mode 100755 index 00000000..c3b66987 --- /dev/null +++ b/docs/_sass/base.scss @@ -0,0 +1,108 @@ +// +// Base element style overrides +// +// stylelint-disable selector-no-type, selector-max-type + +* { + box-sizing: border-box; +} + +::selection { + color: $white; + background: $link-color; +} + +html { + @include fs-4; + scroll-behavior: smooth; +} + +body { + font-family: $body-font-family; + font-size: inherit; + line-height: $body-line-height; + color: $body-text-color; + background-color: $body-background-color; +} + +ol, +ul, +dl, +pre, +address, +blockquote, +table, +div, +hr, +form, +fieldset, +noscript .table-wrapper { + margin-top: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin-top: 0; + margin-bottom: 1em; + font-weight: 500; + line-height: $body-heading-line-height; + color: $body-heading-color; +} + +p { + margin-top: 1em; + margin-bottom: 1em; +} + +a { + color: $link-color; + text-decoration: none; +} + +a:not([class]) { + text-decoration: none; + background-image: linear-gradient($border-color 0%, $border-color 100%); + background-repeat: repeat-x; + background-position: 0 100%; + background-size: 1px 1px; + + &:hover { + background-image: linear-gradient( + rgba($link-color, 0.45) 0%, + rgba($link-color, 0.45) 100% + ); + background-size: 1px 1px; + } +} + +code { + font-family: $mono-font-family; + font-size: 0.75em; + line-height: $body-line-height; +} + +figure, +pre { + margin: 0; +} + +li { + margin: 0.25em 0; +} + +img { + max-width: 100%; + height: auto; +} + +hr { + height: 1px; + padding: 0; + margin: $sp-6 0; + background-color: $border-color; + border: 0; +} diff --git a/docs/_sass/buttons.scss b/docs/_sass/buttons.scss new file mode 100755 index 00000000..57660e05 --- /dev/null +++ b/docs/_sass/buttons.scss @@ -0,0 +1,118 @@ +// +// Buttons and things that look like buttons +// +// stylelint-disable color-named + +.btn { + display: inline-block; + box-sizing: border-box; + padding-top: 0.3em; + padding-right: 1em; + padding-bottom: 0.3em; + padding-left: 1em; + margin: 0; + font-family: inherit; + font-size: inherit; + font-weight: 500; + line-height: 1.5; + color: $link-color; + text-decoration: none; + vertical-align: baseline; + cursor: pointer; + background-color: $base-button-color; + border-width: 0; + border-radius: $border-radius; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + appearance: none; + + &:focus { + text-decoration: none; + outline: none; + box-shadow: 0 0 0 3px rgba(blue, 0.25); + } + + &:focus:hover, + &.selected:focus { + box-shadow: 0 0 0 3px rgba(blue, 0.25); + } + + &:hover, + &.zeroclipboard-is-hover { + color: darken($link-color, 2%); + } + + &:hover, + &:active, + &.zeroclipboard-is-hover, + &.zeroclipboard-is-active { + text-decoration: none; + background-color: darken($base-button-color, 1%); + } + + &:active, + &.selected, + &.zeroclipboard-is-active { + background-color: darken($base-button-color, 3%); + background-image: none; + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15); + } + + &.selected:hover { + background-color: darken(#dcdcdc, 5%); + } + + &:disabled, + &.disabled { + &, + &:hover { + color: rgba(102, 102, 102, 0.5); + cursor: default; + background-color: rgba(229, 229, 229, 0.5); + background-image: none; + box-shadow: none; + } + } +} + +.btn-outline { + color: $link-color; + background: transparent; + box-shadow: inset 0 0 0 2px $grey-lt-300; + + &:hover, + &:active, + &.zeroclipboard-is-hover, + &.zeroclipboard-is-active { + color: darken($link-color, 4%); + text-decoration: none; + background-color: transparent; + box-shadow: inset 0 0 0 3px $grey-lt-300; + } + + &:focus { + text-decoration: none; + outline: none; + box-shadow: inset 0 0 0 2px $grey-dk-100, 0 0 0 3px rgba(blue, 0.25); + } + + &:focus:hover, + &.selected:focus { + box-shadow: inset 0 0 0 2px $grey-dk-100; + } +} + +.btn-primary { + @include btn-color($white, $btn-primary-color); +} + +.btn-purple { + @include btn-color($white, $purple-100); +} + +.btn-blue { + @include btn-color($white, $blue-000); +} + +.btn-green { + @include btn-color($white, $green-100); +} diff --git a/docs/_sass/code.scss b/docs/_sass/code.scss new file mode 100755 index 00000000..ead2c5f5 --- /dev/null +++ b/docs/_sass/code.scss @@ -0,0 +1,334 @@ +// +// Code and syntax highlighting +// +// stylelint-disable selector-no-qualifying-type, declaration-block-semicolon-newline-after,declaration-block-single-line-max-declarations, selector-no-type, selector-max-type + +code { + padding: 0.2em 0.15em; + font-weight: 400; + background-color: $code-background-color; + border: $border $border-color; + border-radius: $border-radius; +} + +// Content structure for highlighted code blocks using fences or Liquid +// +// ```[LANG]...```, no kramdown line_numbers: +// div.[language-LANG.]highlighter-rouge > div.highlight > pre.highlight > code +// +// ```[LANG]...```, kramdown line_numbers = true: +// div.[language-LANG.]highlighter-rouge > div.highlight > pre.highlight > code +// > div.table-wrapper > table.rouge-table > tbody > tr +// > td.rouge-gutter.gl > pre.lineno +// | td.rouge-code > pre +// +// {% highlight LANG %}...{% endhighlight %}: +// figure.highlight > pre > code.language-LANG +// +// {% highlight LANG linenos %}...{% endhighlight %}: +// figure.highlight > pre > code.language-LANG +// > div.table-wrapper > table.rouge-table > tbody > tr +// > td.gutter.gl > pre.lineno +// | td.code > pre +// +// fix_linenos removes the outermost pre when it encloses table.rouge-table +// +// See docs/index-test.md for some tests. +// +// No kramdown line_numbers: fences and Liquid highlighting look the same. +// Kramdown line_numbers = true: fences have a wider gutter than with Liquid? + +// ```[LANG]...``` +div.highlighter-rouge { + padding: $sp-3; + margin-top: 0; + margin-bottom: $sp-3; + background-color: $code-background-color; + border-radius: $border-radius; + box-shadow: none; + -webkit-overflow-scrolling: touch; + + div.highlight, + pre.highlight, + code { + padding: 0; + margin: 0; + border: 0; + } +} + +// {% highlight LANG %}...{% endhighlight %}, +// {% highlight LANG linenos %}...{% endhighlight %}: +figure.highlight { + padding: $sp-3; + margin-top: 0; + margin-bottom: $sp-3; + background-color: $code-background-color; + border-radius: $border-radius; + box-shadow: none; + -webkit-overflow-scrolling: touch; + + pre, + code { + padding: 0; + margin: 0; + border: 0; + } +} + +// ```[LANG]...```, kramdown line_numbers = true, +// {% highlight LANG linenos %}...{% endhighlight %}: +.highlight .table-wrapper { + padding: 0; + margin: 0; + border: 0; + box-shadow: none; + + td, + pre { + @include fs-2; + min-width: 0; + padding: 0; + background-color: $code-background-color; + border: 0; + } + + td.gl { + padding-right: $sp-3; + } + + pre { + margin: 0; + line-height: 2; + } +} + +.highlight .c { + color: #586e75; +} // comment // +.highlight .err { + color: #93a1a1; +} // error // +.highlight .g { + color: #93a1a1; +} // generic // +.highlight .k { + color: #859900; +} // keyword // +.highlight .l { + color: #93a1a1; +} // literal // +.highlight .n { + color: #93a1a1; +} // name // +.highlight .o { + color: #859900; +} // operator // +.highlight .x { + color: #cb4b16; +} // other // +.highlight .p { + color: #93a1a1; +} // punctuation // +.highlight .cm { + color: #586e75; +} // comment.multiline // +.highlight .cp { + color: #859900; +} // comment.preproc // +.highlight .c1 { + color: #586e75; +} // comment.single // +.highlight .cs { + color: #859900; +} // comment.special // +.highlight .gd { + color: #2aa198; +} // generic.deleted // +.highlight .ge { + font-style: italic; + color: #93a1a1; +} // generic.emph // +.highlight .gr { + color: #dc322f; +} // generic.error // +.highlight .gh { + color: #cb4b16; +} // generic.heading // +.highlight .gi { + color: #859900; +} // generic.inserted // +.highlight .go { + color: #93a1a1; +} // generic.output // +.highlight .gp { + color: #93a1a1; +} // generic.prompt // +.highlight .gs { + font-weight: bold; + color: #93a1a1; +} // generic.strong // +.highlight .gu { + color: #cb4b16; +} // generic.subheading // +.highlight .gt { + color: #93a1a1; +} // generic.traceback // +.highlight .kc { + color: #cb4b16; +} // keyword.constant // +.highlight .kd { + color: #268bd2; +} // keyword.declaration // +.highlight .kn { + color: #859900; +} // keyword.namespace // +.highlight .kp { + color: #859900; +} // keyword.pseudo // +.highlight .kr { + color: #268bd2; +} // keyword.reserved // +.highlight .kt { + color: #dc322f; +} // keyword.type // +.highlight .ld { + color: #93a1a1; +} // literal.date // +.highlight .m { + color: #2aa198; +} // literal.number // +.highlight .s { + color: #2aa198; +} // literal.string // +.highlight .na { + color: #555; +} // name.attribute // +.highlight .nb { + color: #b58900; +} // name.builtin // +.highlight .nc { + color: #268bd2; +} // name.class // +.highlight .no { + color: #cb4b16; +} // name.constant // +.highlight .nd { + color: #268bd2; +} // name.decorator // +.highlight .ni { + color: #cb4b16; +} // name.entity // +.highlight .ne { + color: #cb4b16; +} // name.exception // +.highlight .nf { + color: #268bd2; +} // name.function // +.highlight .nl { + color: #555; +} // name.label // +.highlight .nn { + color: #93a1a1; +} // name.namespace // +.highlight .nx { + color: #555; +} // name.other // +.highlight .py { + color: #93a1a1; +} // name.property // +.highlight .nt { + color: #268bd2; +} // name.tag // +.highlight .nv { + color: #268bd2; +} // name.variable // +.highlight .ow { + color: #859900; +} // operator.word // +.highlight .w { + color: #93a1a1; +} // text.whitespace // +.highlight .mf { + color: #2aa198; +} // literal.number.float // +.highlight .mh { + color: #2aa198; +} // literal.number.hex // +.highlight .mi { + color: #2aa198; +} // literal.number.integer // +.highlight .mo { + color: #2aa198; +} // literal.number.oct // +.highlight .sb { + color: #586e75; +} // literal.string.backtick // +.highlight .sc { + color: #2aa198; +} // literal.string.char // +.highlight .sd { + color: #93a1a1; +} // literal.string.doc // +.highlight .s2 { + color: #2aa198; +} // literal.string.double // +.highlight .se { + color: #cb4b16; +} // literal.string.escape // +.highlight .sh { + color: #93a1a1; +} // literal.string.heredoc // +.highlight .si { + color: #2aa198; +} // literal.string.interpol // +.highlight .sx { + color: #2aa198; +} // literal.string.other // +.highlight .sr { + color: #dc322f; +} // literal.string.regex // +.highlight .s1 { + color: #2aa198; +} // literal.string.single // +.highlight .ss { + color: #2aa198; +} // literal.string.symbol // +.highlight .bp { + color: #268bd2; +} // name.builtin.pseudo // +.highlight .vc { + color: #268bd2; +} // name.variable.class // +.highlight .vg { + color: #268bd2; +} // name.variable.global // +.highlight .vi { + color: #268bd2; +} // name.variable.instance // +.highlight .il { + color: #2aa198; +} // literal.number.integer.long // + +// +// Code examples (rendered) +// + +.code-example { + padding: $sp-3; + margin-bottom: $sp-3; + overflow: auto; + border: 1px solid $border-color; + border-radius: $border-radius; + + + .highlighter-rouge, + + figure.highlight { + position: relative; + margin-top: -$sp-4; + border-right: 1px solid $border-color; + border-bottom: 1px solid $border-color; + border-left: 1px solid $border-color; + border-top-left-radius: 0; + border-top-right-radius: 0; + } +} diff --git a/docs/_sass/color_schemes/dark.scss b/docs/_sass/color_schemes/dark.scss new file mode 100755 index 00000000..a25f449c --- /dev/null +++ b/docs/_sass/color_schemes/dark.scss @@ -0,0 +1,17 @@ +$body-background-color: $grey-dk-300; +$sidebar-color: $grey-dk-300; +$border-color: $grey-dk-200; + +$body-text-color: $grey-lt-300; +$body-heading-color: $grey-lt-000; +$nav-child-link-color: $grey-dk-000; +$search-result-preview-color: $grey-dk-000; + +$link-color: $blue-000; +$btn-primary-color: $blue-200; +$base-button-color: $grey-dk-250; + +$code-background-color: $grey-dk-250; +$search-background-color: $grey-dk-250; +$table-background-color: $grey-dk-250; +$feedback-color: darken($sidebar-color, 3%); diff --git a/docs/_sass/color_schemes/light.scss b/docs/_sass/color_schemes/light.scss new file mode 100755 index 00000000..e69de29b diff --git a/docs/_sass/content.scss b/docs/_sass/content.scss new file mode 100755 index 00000000..bc906edd --- /dev/null +++ b/docs/_sass/content.scss @@ -0,0 +1,199 @@ +@charset "UTF-8"; + +// +// Styles for rendered markdown in the .main-content container +// +// stylelint-disable selector-no-type, max-nesting-depth, selector-max-compound-selectors, selector-max-type + +.main-content { + line-height: $content-line-height; + + ol, + ul, + dl, + pre, + address, + blockquote, + .table-wrapper { + margin-top: 0.5em; + } + + a { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + ul, + ol { + padding-left: 1.5em; + } + + li { + .highlight { + margin-top: $sp-1; + } + } + + ol { + list-style-type: none; + counter-reset: step-counter; + + > li { + position: relative; + + &::before { + position: absolute; + top: 0.2em; + left: -1.6em; + color: $grey-dk-000; + content: counter(step-counter); + counter-increment: step-counter; + @include fs-3; + + @include mq(sm) { + top: 0.11em; + } + } + + ol { + counter-reset: sub-counter; + + li { + &::before { + content: counter(sub-counter, lower-alpha); + counter-increment: sub-counter; + } + } + } + } + } + + ul { + list-style: none; + + > li { + &::before { + position: absolute; + margin-left: -1.4em; + color: $grey-dk-000; + content: "•"; + } + } + } + + .task-list { + padding-left: 0; + } + + .task-list-item { + display: flex; + align-items: center; + + &::before { + content: ""; + } + } + + .task-list-item-checkbox { + margin-right: 0.6em; + } + + hr + * { + margin-top: 0; + } + + h1:first-of-type { + margin-top: 0.5em; + } + + dl { + display: grid; + grid-template: auto / 10em 1fr; + } + + dt, + dd { + margin: 0.25em 0; + } + + dt { + grid-column: 1; + font-weight: 500; + text-align: right; + &::after { + content: ":"; + } + } + + dd { + grid-column: 2; + margin-bottom: 0; + margin-left: 1em; + } + + .anchor-heading { + position: absolute; + right: -$sp-4; + width: $sp-5; + height: 100%; + padding-right: $sp-1; + padding-left: $sp-1; + overflow: visible; + + @include mq(md) { + right: auto; + left: -$sp-5; + } + + svg { + display: inline-block; + width: 100%; + height: 100%; + color: $link-color; + visibility: hidden; + } + } + + .anchor-heading:hover, + h1:hover > .anchor-heading, + h2:hover > .anchor-heading, + h3:hover > .anchor-heading, + h4:hover > .anchor-heading, + h5:hover > .anchor-heading, + h6:hover > .anchor-heading { + svg { + visibility: visible; + } + } + + summary { + cursor: pointer; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + position: relative; + margin-top: 1.5em; + margin-bottom: 0.25em; + + &:first-child { + margin-top: $sp-2; + } + + + table, + + .table-wrapper, + + .code-example, + + .highlighter-rouge { + margin-top: 1em; + } + + + p { + margin-top: 0; + } + } +} diff --git a/docs/_sass/labels.scss b/docs/_sass/labels.scss new file mode 100755 index 00000000..e08ae80d --- /dev/null +++ b/docs/_sass/labels.scss @@ -0,0 +1,37 @@ +// +// Labels (not the form kind) +// + +.label, +.label-blue { + display: inline-block; + padding-top: 0.16em; + padding-right: 0.56em; + padding-bottom: 0.16em; + padding-left: 0.56em; + margin-right: $sp-2; + margin-left: $sp-2; + color: $white; + text-transform: uppercase; + vertical-align: middle; + background-color: $blue-100; + @include fs-2; + border-radius: 12px; +} + +.label-green { + background-color: $green-200; +} + +.label-purple { + background-color: $purple-100; +} + +.label-red { + background-color: $red-200; +} + +.label-yellow { + color: $grey-dk-200; + background-color: $yellow-200; +} diff --git a/docs/_sass/layout.scss b/docs/_sass/layout.scss new file mode 100755 index 00000000..004cbe76 --- /dev/null +++ b/docs/_sass/layout.scss @@ -0,0 +1,205 @@ +// +// The basic two column layout +// + +.side-bar { + z-index: 0; + display: flex; + flex-wrap: wrap; + background-color: $sidebar-color; + + @include mq(md) { + flex-wrap: nowrap; + position: fixed; + width: $nav-width-md; + height: 100%; + flex-direction: column; + border-right: $border $border-color; + align-items: flex-end; + } + + @include mq(lg) { + width: calc((100% - #{$nav-width + $content-width}) / 2 + #{$nav-width}); + min-width: $nav-width; + } +} + +.main { + @include mq(md) { + position: relative; + max-width: $content-width; + margin-left: $nav-width-md; + } + + @include mq(lg) { + margin-left: calc( + (100% - #{$nav-width + $content-width}) / 2 + #{$nav-width} + ); + } +} + +.main-content-wrap { + @include container; + padding-top: $gutter-spacing-sm; + padding-bottom: $gutter-spacing-sm; + + @include mq(md) { + padding-top: $gutter-spacing; + padding-bottom: $gutter-spacing; + } +} + +.main-header { + z-index: 0; + display: none; + background-color: $sidebar-color; + + @include mq(md) { + display: flex; + justify-content: space-between; + height: $header-height; + background-color: $body-background-color; + border-bottom: $border $border-color; + } + + &.nav-open { + display: block; + + @include mq(md) { + display: flex; + } + } +} + +.site-nav, +.site-header, +.site-footer { + width: 100%; + + @include mq(lg) { + width: $nav-width; + } +} + +.site-nav { + display: none; + + &.nav-open { + display: block; + } + + @include mq(md) { + display: block; + padding-top: $sp-8; + padding-bottom: $gutter-spacing-sm; + overflow-y: auto; + flex: 1 1 auto; + } +} + +.site-header { + display: flex; + min-height: $header-height; + align-items: center; + + @include mq(md) { + height: $header-height; + max-height: $header-height; + border-bottom: $border $border-color; + } +} + +.site-title { + @include container; + flex-grow: 1; + display: flex; + height: 100%; + align-items: center; + padding-top: $sp-3; + padding-bottom: $sp-3; + color: $body-heading-color; + @include fs-6; + + @include mq(md) { + padding-top: $sp-2; + padding-bottom: $sp-2; + } +} + +@if variable-exists(logo) { + .site-logo { + width: 100%; + height: 100%; + background-image: url($logo); + background-repeat: no-repeat; + background-position: left center; + background-size: contain; + } +} + +.site-button { + display: flex; + height: 100%; + padding: $gutter-spacing-sm; + align-items: center; +} + +@include mq(md) { + .site-header .site-button { + display: none; + } +} + +.site-title:hover { + background-image: linear-gradient( + -90deg, + rgba($feedback-color, 1) 0%, + rgba($feedback-color, 0.8) 80%, + rgba($feedback-color, 0) 100% + ); +} + +.site-button:hover { + background-image: linear-gradient( + -90deg, + rgba($feedback-color, 1) 0%, + rgba($feedback-color, 0.8) 100% + ); +} + +// stylelint-disable selector-max-type + +body { + position: relative; + padding-bottom: $sp-10; + overflow-y: scroll; + + @include mq(md) { + position: static; + padding-bottom: 0; + } +} + +// stylelint-enable selector-max-type + +.site-footer { + @include container; + position: absolute; + bottom: 0; + left: 0; + padding-top: $sp-4; + padding-bottom: $sp-4; + color: $grey-dk-000; + @include fs-2; + + @include mq(md) { + position: static; + justify-self: end; + } +} + +.icon { + width: $sp-5; + height: $sp-5; + color: $link-color; +} diff --git a/docs/_sass/modules.scss b/docs/_sass/modules.scss new file mode 100755 index 00000000..d82591b7 --- /dev/null +++ b/docs/_sass/modules.scss @@ -0,0 +1,20 @@ +// +// Import external dependencies +// +@import "./vendor/normalize.scss/normalize.scss"; + +// +// Modules +// +@import "./base"; +@import "./layout"; +@import "./content"; +@import "./navigation"; +@import "./typography"; +@import "./labels"; +@import "./buttons"; +@import "./search"; +@import "./tables"; +@import "./code"; +@import "./utilities/utilities"; +@import "./print"; diff --git a/docs/_sass/navigation.scss b/docs/_sass/navigation.scss new file mode 100755 index 00000000..521c15fa --- /dev/null +++ b/docs/_sass/navigation.scss @@ -0,0 +1,219 @@ +// +// Main nav, breadcrumb, etc... +// +// stylelint-disable selector-no-type, max-nesting-depth, selector-max-compound-selectors, selector-max-type, selector-max-specificity + +.nav-list { + padding: 0; + margin-top: 0; + margin-bottom: 0; + list-style: none; + + .nav-list-item { + @include fs-4; + position: relative; + margin: 0; + + @include mq(md) { + @include fs-3; + } + + .nav-list-link { + display: block; + min-height: $nav-list-item-height-sm; + padding-top: $sp-1; + padding-bottom: $sp-1; + line-height: #{$nav-list-item-height-sm - 2 * $sp-1}; + @if $nav-list-expander-right { + padding-right: $nav-list-item-height-sm; + padding-left: $gutter-spacing-sm; + } @else { + padding-right: $gutter-spacing-sm; + padding-left: $nav-list-item-height-sm; + } + + @include mq(md) { + min-height: $nav-list-item-height; + line-height: #{$nav-list-item-height - 2 * $sp-1}; + @if $nav-list-expander-right { + padding-right: $nav-list-item-height; + padding-left: $gutter-spacing; + } @else { + padding-right: $gutter-spacing; + padding-left: $nav-list-item-height; + } + } + + &.active { + font-weight: 600; + text-decoration: none; + } + + &:hover, + &.active { + background-image: linear-gradient( + -90deg, + rgba($feedback-color, 1) 0%, + rgba($feedback-color, 0.8) 80%, + rgba($feedback-color, 0) 100% + ); + } + } + + .nav-list-expander { + position: absolute; + @if $nav-list-expander-right { + right: 0; + } + width: $nav-list-item-height-sm; + height: $nav-list-item-height-sm; + padding-top: #{$nav-list-item-height-sm / 4}; + padding-right: #{$nav-list-item-height-sm / 4}; + padding-bottom: #{$nav-list-item-height-sm / 4}; + padding-left: #{$nav-list-item-height-sm / 4}; + color: $link-color; + + @include mq(md) { + width: $nav-list-item-height; + height: $nav-list-item-height; + padding-top: #{$nav-list-item-height / 4}; + padding-right: #{$nav-list-item-height / 4}; + padding-bottom: #{$nav-list-item-height / 4}; + padding-left: #{$nav-list-item-height / 4}; + } + + &:hover { + background-image: linear-gradient( + -90deg, + rgba($feedback-color, 1) 0%, + rgba($feedback-color, 0.8) 100% + ); + } + + @if $nav-list-expander-right { + svg { + transform: rotate(90deg); + } + } + } + + > .nav-list { + display: none; + padding-left: $sp-3; + list-style: none; + + .nav-list-item { + position: relative; + + .nav-list-link { + color: $nav-child-link-color; + } + + .nav-list-expander { + color: $nav-child-link-color; + } + } + } + + &.active { + > .nav-list-expander svg { + @if $nav-list-expander-right { + transform: rotate(-90deg); + } @else { + transform: rotate(90deg); + } + } + + > .nav-list { + display: block; + } + } + } +} + +.nav-category { + padding-top: $sp-2; + padding-right: $gutter-spacing-sm; + padding-bottom: $sp-2; + padding-left: $gutter-spacing-sm; + font-weight: 600; + text-align: end; + text-transform: uppercase; + border-bottom: $border $border-color; + @include fs-2; + + @include mq(md) { + padding-right: $gutter-spacing; + padding-left: $gutter-spacing; + margin-top: $gutter-spacing-sm; + text-align: start; + + &:first-child { + margin-top: 0; + } + } +} + +// Aux nav + +.aux-nav { + height: 100%; + overflow-x: auto; + @include fs-2; + + .aux-nav-list { + display: flex; + height: 100%; + padding: 0; + margin: 0; + list-style: none; + } + + .aux-nav-list-item { + display: inline-block; + height: 100%; + padding: 0; + margin: 0; + } + + @include mq(md) { + padding-right: $gutter-spacing-sm; + } +} + +// Breadcrumb nav + +.breadcrumb-nav { + @include mq(md) { + margin-top: -$sp-4; + } +} + +.breadcrumb-nav-list { + padding-left: 0; + margin-bottom: $sp-3; + list-style: none; +} + +.breadcrumb-nav-list-item { + display: table-cell; + @include fs-2; + + &::before { + display: none; + } + + &::after { + display: inline-block; + margin-right: $sp-2; + margin-left: $sp-2; + color: $grey-dk-000; + content: "/"; + } + + &:last-child { + &::after { + content: ""; + } + } +} diff --git a/docs/_sass/print.scss b/docs/_sass/print.scss new file mode 100755 index 00000000..6e6de373 --- /dev/null +++ b/docs/_sass/print.scss @@ -0,0 +1,40 @@ +// stylelint-disable selector-max-specificity, selector-max-id, selector-max-type, selector-no-qualifying-type, primer/no-override, + +@media print { + .site-footer, + .site-button, + #edit-this-page, + #back-to-top, + .site-nav, + .main-header { + display: none !important; + } + + .side-bar { + width: 100%; + height: auto; + border-right: 0 !important; + } + + .site-header { + border-bottom: 1px solid $border-color; + } + + .site-title { + font-size: $root-font-size !important; + font-weight: 700 !important; + } + + .text-small { + font-size: 8pt !important; + } + + pre.highlight { + border: 1px solid $border-color; + } + + .main { + max-width: none; + margin-left: 0; + } +} diff --git a/docs/_sass/search.scss b/docs/_sass/search.scss new file mode 100755 index 00000000..4290210d --- /dev/null +++ b/docs/_sass/search.scss @@ -0,0 +1,323 @@ +// +// Search input and autocomplete +// + +.search { + position: relative; + z-index: 2; + flex-grow: 1; + height: $sp-10; + padding: $sp-2; + transition: padding linear #{$transition-duration / 2}; + + @include mq(md) { + position: relative !important; + width: auto !important; + height: 100% !important; + padding: 0; + transition: none; + } +} + +.search-input-wrap { + position: relative; + z-index: 1; + height: $sp-8; + overflow: hidden; + border-radius: $border-radius; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + transition: height linear #{$transition-duration / 2}; + + @include mq(md) { + position: absolute; + width: 100%; + max-width: $search-results-width; + height: 100% !important; + border-radius: 0; + box-shadow: none; + transition: width ease $transition-duration; + } +} + +.search-input { + position: absolute; + width: 100%; + height: 100%; + padding-top: $sp-2; + padding-right: $gutter-spacing-sm; + padding-bottom: $sp-2; + padding-left: #{$gutter-spacing-sm + $sp-5}; + font-size: 16px; + background-color: $search-background-color; + border-top: 0; + border-right: 0; + border-bottom: 0; + border-left: 0; + border-radius: 0; + + @include mq(md) { + padding-top: $gutter-spacing-sm; + padding-bottom: $gutter-spacing-sm; + padding-left: #{$gutter-spacing + $sp-5}; + font-size: 14px; + background-color: $body-background-color; + transition: padding-left linear #{$transition-duration / 2}; + } + + &:focus { + outline: 0; + + + .search-label .search-icon { + color: $link-color; + } + } +} + +.search-label { + position: absolute; + display: flex; + height: 100%; + padding-left: $gutter-spacing-sm; + + @include mq(md) { + padding-left: $gutter-spacing; + transition: padding-left linear #{$transition-duration / 2}; + } + + .search-icon { + width: #{$sp-4 * 1.2}; + height: #{$sp-4 * 1.2}; + align-self: center; + color: $grey-dk-000; + } +} + +.search-results { + position: absolute; + left: 0; + display: none; + width: 100%; + max-height: calc(100% - #{$sp-10}); + overflow-y: auto; + background-color: $search-background-color; + border-bottom-right-radius: $border-radius; + border-bottom-left-radius: $border-radius; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + + @include mq(md) { + top: 100%; + width: $search-results-width; + max-height: calc(100vh - 200%) !important; + } +} + +.search-results-list { + padding-left: 0; + margin-bottom: $sp-1; + list-style: none; + @include fs-4; + + @include mq(md) { + @include fs-3; + } +} + +.search-results-list-item { + padding: 0; + margin: 0; +} + +.search-result { + display: block; + padding-top: $sp-1; + padding-right: $sp-3; + padding-bottom: $sp-1; + padding-left: $sp-3; + + &:hover, + &.active { + background-color: $feedback-color; + } +} + +.search-result-title { + display: block; + padding-top: $sp-2; + padding-bottom: $sp-2; + + @include mq(sm) { + display: inline-block; + width: 40%; + padding-right: $sp-2; + vertical-align: top; + } +} + +.search-result-doc { + display: flex; + align-items: center; + word-wrap: break-word; + + &.search-result-doc-parent { + opacity: 0.5; + @include fs-3; + + @include mq(md) { + @include fs-2; + } + } + + .search-result-icon { + width: $sp-4; + height: $sp-4; + margin-right: $sp-2; + color: $link-color; + flex-shrink: 0; + } + + .search-result-doc-title { + overflow: auto; + } +} + +.search-result-section { + margin-left: #{$sp-4 + $sp-2}; + word-wrap: break-word; +} + +.search-result-rel-url { + display: block; + margin-left: #{$sp-4 + $sp-2}; + overflow: hidden; + color: $search-result-preview-color; + text-overflow: ellipsis; + white-space: nowrap; + @include fs-1; +} + +.search-result-previews { + display: block; + padding-top: $sp-2; + padding-bottom: $sp-2; + padding-left: $sp-4; + margin-left: $sp-2; + color: $search-result-preview-color; + word-wrap: break-word; + border-left: $border; + border-left-color: $border-color; + @include fs-2; + + @include mq(sm) { + display: inline-block; + width: 60%; + padding-left: $sp-2; + margin-left: 0; + vertical-align: top; + } +} + +.search-result-preview + .search-result-preview { + margin-top: $sp-1; +} + +.search-result-highlight { + font-weight: bold; +} + +.search-no-result { + padding-top: $sp-2; + padding-right: $sp-3; + padding-bottom: $sp-2; + padding-left: $sp-3; + @include fs-3; +} + +.search-button { + position: fixed; + right: $sp-4; + bottom: $sp-4; + display: flex; + width: $sp-9; + height: $sp-9; + background-color: $search-background-color; + border: 1px solid rgba($link-color, 0.3); + border-radius: #{$sp-9 / 2}; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + align-items: center; + justify-content: center; +} + +.search-overlay { + position: fixed; + top: 0; + left: 0; + z-index: 1; + width: 0; + height: 0; + background-color: rgba(0, 0, 0, 0.3); + opacity: 0; + transition: opacity ease $transition-duration, width 0s $transition-duration, + height 0s $transition-duration; +} + +.search-active { + .search { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 0; + } + + .search-input-wrap { + height: $sp-10; + border-radius: 0; + + @include mq(md) { + width: $search-results-width; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + } + } + + .search-input { + background-color: $search-background-color; + + @include mq(md) { + padding-left: 2.3rem; + } + } + + .search-label { + @include mq(md) { + padding-left: 0.6rem; + } + } + + .search-results { + display: block; + } + + .search-overlay { + width: 100%; + height: 100%; + opacity: 1; + transition: opacity ease $transition-duration, width 0s, height 0s; + } + + @include mq(md) { + .main { + position: fixed; + right: 0; + left: 0; + } + } + + .main-header { + padding-top: $sp-10; + + @include mq(md) { + padding-top: 0; + } + } +} diff --git a/docs/_sass/support/_functions.scss b/docs/_sass/support/_functions.scss new file mode 100755 index 00000000..6772f4e4 --- /dev/null +++ b/docs/_sass/support/_functions.scss @@ -0,0 +1,9 @@ +@function rem($size, $unit: "") { + $remSize: $size / $root-font-size; + + @if ($unit == false) { + @return #{$remSize}; + } @else { + @return #{$remSize}rem; + } +} diff --git a/docs/_sass/support/_variables.scss b/docs/_sass/support/_variables.scss new file mode 100755 index 00000000..3ab3f05e --- /dev/null +++ b/docs/_sass/support/_variables.scss @@ -0,0 +1,153 @@ +// +// Typography +// + +$body-font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", + Roboto, "Helvetica Neue", Arial, sans-serif !default; +$mono-font-family: "SFMono-Regular", Menlo, Consolas, Monospace !default; +$root-font-size: 16px !default; // Base font-size for rems +$body-line-height: 1.4 !default; +$content-line-height: 1.6 !default; +$body-heading-line-height: 1.25 !default; + +// +// Font size +// `-sm` suffix is the size at the small (and above) media query +// + +$font-size-1: 9px !default; +$font-size-1-sm: 10px !default; +$font-size-2: 11px !default; //h4 - uppercased!, h6 not uppercased, text-small +$font-size-3: 12px !default; //h5 +$font-size-4: 14px !default; +$font-size-5: 16px !default; //h3 +$font-size-6: 18px !default; //h2 +$font-size-7: 24px !default; +$font-size-8: 32px !default; //h1 +$font-size-9: 36px !default; +$font-size-10: 42px !default; +$font-size-10-sm: 48px !default; + +// +// Colors +// + +$white: #fff !default; + +$grey-dk-000: #959396 !default; +$grey-dk-100: #5c5962 !default; +$grey-dk-200: #44434d !default; +$grey-dk-250: #302d36 !default; +$grey-dk-300: #27262b !default; + +$grey-lt-000: #f5f6fa !default; +$grey-lt-100: #eeebee !default; +$grey-lt-200: #ecebed !default; +$grey-lt-300: #e6e1e8 !default; + +$purple-000: #7253ed !default; +$purple-100: #5e41d0 !default; +$purple-200: #4e26af !default; +$purple-300: #381885 !default; + +$blue-000: #2c84fa !default; +$blue-100: #2869e6 !default; +$blue-200: #264caf !default; +$blue-300: #183385 !default; + +$green-000: #41d693 !default; +$green-100: #11b584 !default; +$green-200: #009c7b !default; +$green-300: #026e57 !default; + +$yellow-000: #ffeb82 !default; +$yellow-100: #fadf50 !default; +$yellow-200: #f7d12e !default; +$yellow-300: #e7af06 !default; + +$red-000: #f77e7e !default; +$red-100: #f96e65 !default; +$red-200: #e94c4c !default; +$red-300: #dd2e2e !default; + +$body-background-color: $white !default; +$sidebar-color: $grey-lt-000 !default; +$search-background-color: $white !default; +$table-background-color: $white !default; +$code-background-color: $grey-lt-000 !default; +$feedback-color: darken($sidebar-color, 3%) !default; + +$body-text-color: $grey-dk-100 !default; +$body-heading-color: $grey-dk-300 !default; +$search-result-preview-color: $grey-dk-000 !default; +$nav-child-link-color: $grey-dk-100 !default; +$link-color: $purple-000 !default; +$btn-primary-color: $purple-100 !default; +$base-button-color: #f7f7f7 !default; + +// +// Spacing +// + +$spacing-unit: 1rem; // 1rem == 16px + +$spacers: ( + sp-0: 0, + sp-1: $spacing-unit * 0.25, + sp-2: $spacing-unit * 0.5, + sp-3: $spacing-unit * 0.75, + sp-4: $spacing-unit, + sp-5: $spacing-unit * 1.5, + sp-6: $spacing-unit * 2, + sp-7: $spacing-unit * 2.5, + sp-8: $spacing-unit * 3, + sp-9: $spacing-unit * 3.5, + sp-10: $spacing-unit * 4, +) !default; + +$sp-1: map-get($spacers, sp-1) !default; // 0.25 rem == 4px +$sp-2: map-get($spacers, sp-2) !default; // 0.5 rem == 8px +$sp-3: map-get($spacers, sp-3) !default; // 0.75 rem == 12px +$sp-4: map-get($spacers, sp-4) !default; // 1 rem == 16px +$sp-5: map-get($spacers, sp-5) !default; // 1.5 rem == 24px +$sp-6: map-get($spacers, sp-6) !default; // 2 rem == 32px +$sp-7: map-get($spacers, sp-7) !default; // 2.5 rem == 40px +$sp-8: map-get($spacers, sp-8) !default; // 3 rem == 48px +$sp-9: map-get($spacers, sp-9) !default; // 3.5 rem == 56px +$sp-10: map-get($spacers, sp-10) !default; // 4 rem == 64px + +// +// Borders +// + +$border: 1px solid !default; +$border-radius: 4px !default; +$border-color: $grey-lt-100 !default; + +// +// Grid system +// + +$gutter-spacing: $sp-6 !default; +$gutter-spacing-sm: $sp-4 !default; +$nav-width: 264px !default; +$nav-width-md: 248px !default; +$nav-list-item-height: $sp-6 !default; +$nav-list-item-height-sm: $sp-8 !default; +$nav-list-expander-right: true; +$content-width: 800px !default; +$header-height: 60px !default; +$search-results-width: $content-width - $nav-width !default; +$transition-duration: 400ms; + +// +// Media queries in pixels +// + +$media-queries: ( + xs: 320px, + sm: 500px, + md: $content-width, + lg: $content-width + $nav-width, + xl: 1400px, +) !default; diff --git a/docs/_sass/support/mixins/_buttons.scss b/docs/_sass/support/mixins/_buttons.scss new file mode 100755 index 00000000..e3e6c4fb --- /dev/null +++ b/docs/_sass/support/mixins/_buttons.scss @@ -0,0 +1,27 @@ +// Colored button + +@mixin btn-color($fg, $bg) { + color: $fg; + background-color: darken($bg, 2%); + background-image: linear-gradient(lighten($bg, 5%), darken($bg, 2%)); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), 0 4px 10px rgba(0, 0, 0, 0.12); + + &:hover, + &.zeroclipboard-is-hover { + color: $fg; + background-color: darken($bg, 4%); + background-image: linear-gradient((lighten($bg, 2%), darken($bg, 4%))); + } + + &:active, + &.selected, + &.zeroclipboard-is-active { + background-color: darken($bg, 5%); + background-image: none; + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15); + } + + &.selected:hover { + background-color: darken($bg, 10%); + } +} diff --git a/docs/_sass/support/mixins/_layout.scss b/docs/_sass/support/mixins/_layout.scss new file mode 100755 index 00000000..27ad6c7d --- /dev/null +++ b/docs/_sass/support/mixins/_layout.scss @@ -0,0 +1,34 @@ +// Media query + +// Media query mixin +// Usage: +// @include mq(md) { +// ..medium and up styles +// } +@mixin mq($name) { + // Retrieves the value from the key + $value: map-get($media-queries, $name); + + // If the key exists in the map + @if $value != null { + // Prints a media query based on the value + @media (min-width: rem($value)) { + @content; + } + } @else { + @warn "No value could be retrieved from `#{$media-query}`. " + + "Please make sure it is defined in `$media-queries` map."; + } +} + +// Responsive container + +@mixin container { + padding-right: $gutter-spacing-sm; + padding-left: $gutter-spacing-sm; + + @include mq(md) { + padding-right: $gutter-spacing; + padding-left: $gutter-spacing; + } +} diff --git a/docs/_sass/support/mixins/_typography.scss b/docs/_sass/support/mixins/_typography.scss new file mode 100755 index 00000000..5207fcd1 --- /dev/null +++ b/docs/_sass/support/mixins/_typography.scss @@ -0,0 +1,84 @@ +@mixin fs-1 { + font-size: $font-size-1 !important; + + @include mq(sm) { + font-size: $font-size-1-sm !important; + } +} + +@mixin fs-2 { + font-size: $font-size-2 !important; + + @include mq(sm) { + font-size: $font-size-3 !important; + } +} + +@mixin fs-3 { + font-size: $font-size-3 !important; + + @include mq(sm) { + font-size: $font-size-4 !important; + } +} + +@mixin fs-4 { + font-size: $font-size-4 !important; + + @include mq(sm) { + font-size: $font-size-5 !important; + } +} + +@mixin fs-5 { + font-size: $font-size-5 !important; + + @include mq(sm) { + font-size: $font-size-6 !important; + } +} + +@mixin fs-6 { + font-size: $font-size-6 !important; + + @include mq(sm) { + font-size: $font-size-7 !important; + line-height: $body-heading-line-height; + } +} + +@mixin fs-7 { + font-size: $font-size-7 !important; + line-height: $body-heading-line-height; + + @include mq(sm) { + font-size: $font-size-8 !important; + } +} + +@mixin fs-8 { + font-size: $font-size-8 !important; + line-height: $body-heading-line-height; + + @include mq(sm) { + font-size: $font-size-9 !important; + } +} + +@mixin fs-9 { + font-size: $font-size-9 !important; + line-height: $body-heading-line-height; + + @include mq(sm) { + font-size: $font-size-10 !important; + } +} + +@mixin fs-10 { + font-size: $font-size-10 !important; + line-height: $body-heading-line-height; + + @include mq(sm) { + font-size: $font-size-10-sm !important; + } +} diff --git a/docs/_sass/support/mixins/mixins.scss b/docs/_sass/support/mixins/mixins.scss new file mode 100755 index 00000000..0506fbf5 --- /dev/null +++ b/docs/_sass/support/mixins/mixins.scss @@ -0,0 +1,3 @@ +@import "./layout"; +@import "./buttons"; +@import "./typography"; diff --git a/docs/_sass/support/support.scss b/docs/_sass/support/support.scss new file mode 100755 index 00000000..8131a320 --- /dev/null +++ b/docs/_sass/support/support.scss @@ -0,0 +1,3 @@ +@import "./variables"; +@import "./functions"; +@import "./mixins/mixins"; diff --git a/docs/_sass/tables.scss b/docs/_sass/tables.scss new file mode 100755 index 00000000..b2ac7cdb --- /dev/null +++ b/docs/_sass/tables.scss @@ -0,0 +1,58 @@ +// +// Tables +// +// stylelint-disable max-nesting-depth, selector-no-type, selector-max-type + +.table-wrapper { + display: block; + width: 100%; + max-width: 100%; + margin-bottom: $sp-5; + overflow-x: auto; + border-radius: $border-radius; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); +} + +table { + display: table; + min-width: 100%; + border-collapse: separate; +} + +th, +td { + @include fs-3; + min-width: 120px; + padding-top: $sp-2; + padding-right: $sp-3; + padding-bottom: $sp-2; + padding-left: $sp-3; + background-color: $table-background-color; + border-bottom: $border rgba($border-color, 0.5); + border-left: $border $border-color; + + &:first-of-type { + border-left: 0; + } +} + +tbody { + tr { + &:last-of-type { + th, + td { + border-bottom: 0; + } + + td { + padding-bottom: $sp-3; + } + } + } +} + +thead { + th { + border-bottom: $border $border-color; + } +} diff --git a/docs/_sass/typography.scss b/docs/_sass/typography.scss new file mode 100755 index 00000000..cadee362 --- /dev/null +++ b/docs/_sass/typography.scss @@ -0,0 +1,64 @@ +// +// Typography +// +// stylelint-disable primer/selector-no-utility, primer/no-override, selector-no-type, selector-max-type + +h1, +.text-alpha { + @include fs-8; + font-weight: 300; +} + +h2, +.text-beta { + @include fs-6; +} + +h3, +.text-gamma { + @include fs-5; +} + +h4, +.text-delta { + @include fs-2; + font-weight: 400; + text-transform: uppercase; + letter-spacing: 0.1em; +} + +h4 code { + text-transform: none; +} + +h5, +.text-epsilon { + @include fs-3; + color: $grey-dk-200; +} + +h6, +.text-zeta { + @include fs-2; + color: $grey-dk-200; +} + +.text-small { + @include fs-2; +} + +.text-mono { + font-family: $mono-font-family !important; +} + +.text-left { + text-align: left !important; +} + +.text-center { + text-align: center !important; +} + +.text-right { + text-align: right !important; +} diff --git a/docs/_sass/utilities/_colors.scss b/docs/_sass/utilities/_colors.scss new file mode 100755 index 00000000..f3607ab8 --- /dev/null +++ b/docs/_sass/utilities/_colors.scss @@ -0,0 +1,239 @@ +// +// Utility classes for colors +// + +// Text colors + +.text-grey-dk-000 { + color: $grey-dk-000 !important; +} + +.text-grey-dk-100 { + color: $grey-dk-100 !important; +} + +.text-grey-dk-200 { + color: $grey-dk-200 !important; +} + +.text-grey-dk-250 { + color: $grey-dk-250 !important; +} + +.text-grey-dk-300 { + color: $grey-dk-300 !important; +} + +.text-grey-lt-000 { + color: $grey-lt-000 !important; +} + +.text-grey-lt-100 { + color: $grey-lt-100 !important; +} + +.text-grey-lt-200 { + color: $grey-lt-200 !important; +} + +.text-grey-lt-300 { + color: $grey-lt-300 !important; +} + +.text-blue-000 { + color: $blue-000 !important; +} + +.text-blue-100 { + color: $blue-100 !important; +} + +.text-blue-200 { + color: $blue-200 !important; +} + +.text-blue-300 { + color: $blue-300 !important; +} + +.text-green-000 { + color: $green-000 !important; +} + +.text-green-100 { + color: $green-100 !important; +} + +.text-green-200 { + color: $green-200 !important; +} + +.text-green-300 { + color: $green-300 !important; +} + +.text-purple-000 { + color: $purple-000 !important; +} + +.text-purple-100 { + color: $purple-100 !important; +} + +.text-purple-200 { + color: $purple-200 !important; +} + +.text-purple-300 { + color: $purple-300 !important; +} + +.text-yellow-000 { + color: $yellow-000 !important; +} + +.text-yellow-100 { + color: $yellow-100 !important; +} + +.text-yellow-200 { + color: $yellow-200 !important; +} + +.text-yellow-300 { + color: $yellow-300 !important; +} + +.text-red-000 { + color: $red-000 !important; +} + +.text-red-100 { + color: $red-100 !important; +} + +.text-red-200 { + color: $red-200 !important; +} + +.text-red-300 { + color: $red-300 !important; +} + +// Background colors + +.bg-grey-dk-000 { + background-color: $grey-dk-000 !important; +} + +.bg-grey-dk-100 { + background-color: $grey-dk-100 !important; +} + +.bg-grey-dk-200 { + background-color: $grey-dk-200 !important; +} + +.bg-grey-dk-250 { + background-color: $grey-dk-250 !important; +} + +.bg-grey-dk-300 { + background-color: $grey-dk-300 !important; +} + +.bg-grey-lt-000 { + background-color: $grey-lt-000 !important; +} + +.bg-grey-lt-100 { + background-color: $grey-lt-100 !important; +} + +.bg-grey-lt-200 { + background-color: $grey-lt-200 !important; +} + +.bg-grey-lt-300 { + background-color: $grey-lt-300 !important; +} + +.bg-blue-000 { + background-color: $blue-000 !important; +} + +.bg-blue-100 { + background-color: $blue-100 !important; +} + +.bg-blue-200 { + background-color: $blue-200 !important; +} + +.bg-blue-300 { + background-color: $blue-300 !important; +} + +.bg-green-000 { + background-color: $green-000 !important; +} + +.bg-green-100 { + background-color: $green-100 !important; +} + +.bg-green-200 { + background-color: $green-200 !important; +} + +.bg-green-300 { + background-color: $green-300 !important; +} + +.bg-purple-000 { + background-color: $purple-000 !important; +} + +.bg-purple-100 { + background-color: $purple-100 !important; +} + +.bg-purple-200 { + background-color: $purple-200 !important; +} + +.bg-purple-300 { + background-color: $purple-300 !important; +} + +.bg-yellow-000 { + background-color: $yellow-000 !important; +} + +.bg-yellow-100 { + background-color: $yellow-100 !important; +} + +.bg-yellow-200 { + background-color: $yellow-200 !important; +} + +.bg-yellow-300 { + background-color: $yellow-300 !important; +} + +.bg-red-000 { + background-color: $red-000 !important; +} + +.bg-red-100 { + background-color: $red-100 !important; +} + +.bg-red-200 { + background-color: $red-200 !important; +} + +.bg-red-300 { + background-color: $red-300 !important; +} diff --git a/docs/_sass/utilities/_layout.scss b/docs/_sass/utilities/_layout.scss new file mode 100755 index 00000000..37ebe421 --- /dev/null +++ b/docs/_sass/utilities/_layout.scss @@ -0,0 +1,95 @@ +// stylelint-disable primer/selector-no-utility, primer/no-override +// +// Utility classes for layout +// + +// Display + +.d-block { + display: block !important; +} +.d-flex { + display: flex !important; +} +.d-inline { + display: inline !important; +} +.d-inline-block { + display: inline-block !important; +} +.d-none { + display: none !important; +} + +@each $media-query in map-keys($media-queries) { + @for $i from 1 through length($spacers) { + @include mq($media-query) { + $size: #{map-get($spacers, sp-#{$i - 1})}; + $scale: #{$i - 1}; + + // .d-sm-block, .d-md-none, .d-lg-inline + .d-#{$media-query}-block { + display: block !important; + } + .d-#{$media-query}-flex { + display: flex !important; + } + .d-#{$media-query}-inline { + display: inline !important; + } + .d-#{$media-query}-inline-block { + display: inline-block !important; + } + .d-#{$media-query}-none { + display: none !important; + } + } + } +} + +// Horizontal alignment + +.float-left { + float: left !important; +} + +.float-right { + float: right !important; +} + +.flex-justify-start { + justify-content: flex-start !important; +} + +.flex-justify-end { + justify-content: flex-end !important; +} + +.flex-justify-between { + justify-content: space-between !important; +} + +.flex-justify-around { + justify-content: space-around !important; +} + +// Vertical alignment + +.v-align-baseline { + vertical-align: baseline !important; +} +.v-align-bottom { + vertical-align: bottom !important; +} +.v-align-middle { + vertical-align: middle !important; +} +.v-align-text-bottom { + vertical-align: text-bottom !important; +} +.v-align-text-top { + vertical-align: text-top !important; +} +.v-align-top { + vertical-align: top !important; +} diff --git a/docs/_sass/utilities/_lists.scss b/docs/_sass/utilities/_lists.scss new file mode 100755 index 00000000..c7b2293d --- /dev/null +++ b/docs/_sass/utilities/_lists.scss @@ -0,0 +1,17 @@ +// +// Utility classes for lists +// + +// stylelint-disable primer/selector-no-utility, primer/no-override, selector-max-type + +.list-style-none { + padding: 0 !important; + margin: 0 !important; + list-style: none !important; + + li { + &::before { + display: none !important; + } + } +} diff --git a/docs/_sass/utilities/_spacing.scss b/docs/_sass/utilities/_spacing.scss new file mode 100755 index 00000000..162f8017 --- /dev/null +++ b/docs/_sass/utilities/_spacing.scss @@ -0,0 +1,165 @@ +// +// Utility classes for margins and padding +// + +// scss-lint:disable SpaceAfterPropertyName +// stylelint-disable block-opening-brace-space-after, block-opening-brace-space-before, primer/selector-no-utility, primer/no-override + +// Margin spacer utilities + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +@for $i from 1 through length($spacers) { + $size: #{map-get($spacers, sp-#{$i - 1})}; + $scale: #{$i - 1}; + + // .m-0, .m-1, .m-2... + .m-#{$scale} { + margin: #{$size} !important; + } + .mt-#{$scale} { + margin-top: #{$size} !important; + } + .mr-#{$scale} { + margin-right: #{$size} !important; + } + .mb-#{$scale} { + margin-bottom: #{$size} !important; + } + .ml-#{$scale} { + margin-left: #{$size} !important; + } + + .mx-#{$scale} { + margin-right: #{$size} !important; + margin-left: #{$size} !important; + } + + .my-#{$scale} { + margin-top: #{$size} !important; + margin-bottom: #{$size} !important; + } + + .mxn-#{$scale} { + margin-right: -#{$size} !important; + margin-left: -#{$size} !important; + } + .mx-#{$scale}-auto { + margin-right: auto !important; + margin-left: auto !important; + } +} + +@each $media-query in map-keys($media-queries) { + @for $i from 1 through length($spacers) { + @include mq($media-query) { + $size: #{map-get($spacers, sp-#{$i - 1})}; + $scale: #{$i - 1}; + + // .m-sm-0, .m-md-1, .m-lg-2... + .m-#{$media-query}-#{$scale} { + margin: #{$size} !important; + } + .mt-#{$media-query}-#{$scale} { + margin-top: #{$size} !important; + } + .mr-#{$media-query}-#{$scale} { + margin-right: #{$size} !important; + } + .mb-#{$media-query}-#{$scale} { + margin-bottom: #{$size} !important; + } + .ml-#{$media-query}-#{$scale} { + margin-left: #{$size} !important; + } + + .mx-#{$media-query}-#{$scale} { + margin-right: #{$size} !important; + margin-left: #{$size} !important; + } + + .my-#{$media-query}-#{$scale} { + margin-top: #{$size} !important; + margin-bottom: #{$size} !important; + } + + .mxn-#{$media-query}-#{$scale} { + margin-right: -#{$size} !important; + margin-left: -#{$size} !important; + } + } + } +} + +// Padding spacer utilities + +@for $i from 1 through length($spacers) { + $size: #{map-get($spacers, sp-#{$i - 1})}; + $scale: #{$i - 1}; + + // .p-0, .p-1, .p-2... + .p-#{$scale} { + padding: #{$size} !important; + } + .pt-#{$scale} { + padding-top: #{$size} !important; + } + .pr-#{$scale} { + padding-right: #{$size} !important; + } + .pb-#{$scale} { + padding-bottom: #{$size} !important; + } + .pl-#{$scale} { + padding-left: #{$size} !important; + } + + .px-#{$scale} { + padding-right: #{$size} !important; + padding-left: #{$size} !important; + } + + .py-#{$scale} { + padding-top: #{$size} !important; + padding-bottom: #{$size} !important; + } +} + +@each $media-query in map-keys($media-queries) { + @include mq($media-query) { + @for $i from 1 through length($spacers) { + $size: #{map-get($spacers, sp-#{$i - 1})}; + $scale: #{$i - 1}; + + // .p-sm-0, .p-md-1, .p-lg-2... + .p-#{$media-query}-#{$scale} { + padding: #{$size} !important; + } + .pt-#{$media-query}-#{$scale} { + padding-top: #{$size} !important; + } + .pr-#{$media-query}-#{$scale} { + padding-right: #{$size} !important; + } + .pb-#{$media-query}-#{$scale} { + padding-bottom: #{$size} !important; + } + .pl-#{$media-query}-#{$scale} { + padding-left: #{$size} !important; + } + + .px-#{$media-query}-#{$scale} { + padding-right: #{$size} !important; + padding-left: #{$size} !important; + } + + .py-#{$media-query}-#{$scale} { + padding-top: #{$size} !important; + padding-bottom: #{$size} !important; + } + } + } +} diff --git a/docs/_sass/utilities/_typography.scss b/docs/_sass/utilities/_typography.scss new file mode 100755 index 00000000..2397acbc --- /dev/null +++ b/docs/_sass/utilities/_typography.scss @@ -0,0 +1,91 @@ +// +// Utility classes for typography +// + +// stylelint-disable primer/selector-no-utility, primer/no-override + +.fs-1 { + @include fs-1; +} + +.fs-2 { + @include fs-2; +} + +.fs-3 { + @include fs-3; +} + +.fs-4 { + @include fs-4; +} + +.fs-5 { + @include fs-5; +} + +.fs-6 { + @include fs-6; +} + +.fs-7 { + @include fs-7; +} + +.fs-8 { + @include fs-8; +} + +.fs-9 { + @include fs-9; +} + +.fs-10 { + @include fs-10; +} + +.fw-300 { + font-weight: 300 !important; +} + +.fw-400 { + font-weight: 400 !important; +} + +.fw-500 { + font-weight: 500 !important; +} + +.fw-700 { + font-weight: 700 !important; +} + +.lh-0 { + line-height: 0 !important; +} + +.lh-default { + line-height: $body-line-height; +} + +.lh-tight { + line-height: $body-heading-line-height; +} + +.ls-5 { + letter-spacing: 0.05em !important; +} + +.ls-10 { + letter-spacing: 0.1em !important; +} + +.ls-0 { + letter-spacing: 0 !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +// stylelint-enable primer/selector-no-utility diff --git a/docs/_sass/utilities/utilities.scss b/docs/_sass/utilities/utilities.scss new file mode 100755 index 00000000..6c25bdfa --- /dev/null +++ b/docs/_sass/utilities/utilities.scss @@ -0,0 +1,5 @@ +@import "./colors"; +@import "./layout"; +@import "./typography"; +@import "./lists"; +@import "./spacing"; diff --git a/docs/_sass/vendor/normalize.scss/README.md b/docs/_sass/vendor/normalize.scss/README.md new file mode 100755 index 00000000..36cc1c6a --- /dev/null +++ b/docs/_sass/vendor/normalize.scss/README.md @@ -0,0 +1,78 @@ +# normalize.scss v0.1.0 + +Normalize.scss is the SCSS version of [normalize.css](http://necolas.github.io/normalize.css), a customisable CSS file that makes browsers render all elements more consistently and in line with modern standards. + +[View the normalize.css test file](http://necolas.github.io/normalize.css/latest/test.html) + +## Install + +* [npm](http://npmjs.org/): `npm install --save normalize.scss` +* [Component(1)](https://github.com/component/component/): `component install guerrero/normalize.scss` +* [Bower](http://bower.io/): `bower install --save normalize.scss` +* Download: Go to [this link](https://raw.githubusercontent.com/guerrero/normalize.scss/master/normalize.scss), press right-click on the page and choose "Save as..." + +No other styles should come before Normalize.scss. + +It's recommendable to modify `normalize.scss` to suit it to your project + +## What does it do? + +* Preserves useful defaults, unlike many CSS resets. +* Normalizes styles for a wide range of elements. +* Corrects bugs and common browser inconsistencies. +* Improves usability with subtle improvements. +* Explains what code does using detailed comments. + +## Browser support + +* Google Chrome (latest) +* Mozilla Firefox (latest) +* Mozilla Firefox 4 +* Opera (latest) +* Apple Safari 6+ +* Internet Explorer 8+ + +[Normalize.css v1 provides legacy browser +support](https://github.com/necolas/normalize.css/tree/v1) (IE 6+, Safari 4+), +but is no longer actively developed. + +## Extended details + +Additional detail and explanation of the esoteric parts of normalize.css. + +#### `pre, code, kbd, samp` + +The `font-family: monospace, monospace` hack fixes the inheritance and scaling +of font-size for preformated text. The duplication of `monospace` is +intentional. [Source](http://en.wikipedia.org/wiki/User:Davidgothberg/Test59). + +#### `sub, sup` + +Normally, using `sub` or `sup` affects the line-box height of text in all +browsers. [Source](http://gist.github.com/413930). + +#### `svg:not(:root)` + +Adding `overflow: hidden` fixes IE9's SVG rendering. Earlier versions of IE +don't support SVG, so we can safely use the `:not()` and `:root` selectors that +modern browsers use in the default UA stylesheets to apply this style. [SVG +Mailing List discussion](http://lists.w3.org/Archives/Public/public-svg-wg/2008JulSep/0339.html) + +#### `input[type="search"]` + +The search input is not fully stylable by default. In Chrome and Safari on +OSX/iOS you can't control `font`, `padding`, `border`, or `background`. In +Chrome and Safari on Windows you can't control `border` properly. It will apply +`border-width` but will only show a border color (which cannot be controlled) +for the outer 1px of that border. Applying `-webkit-appearance: textfield` +addresses these issues without removing the benefits of search inputs (e.g. +showing past searches). + +#### `legend` + +Adding `border: 0` corrects an IE 8–11 bug where `color` (yes, `color`) is not +inherited by `legend`. + +## Acknowledgements + +Normalize.scss is a project by [Alex Guerrero](https://github.com/guerrero) based on [normalize.css](http://necolas.github.io/normalize.css) from [Nicolas Gallagher](https://github.com/necolas), co-created with [Jonathan Neal](https://github.com/jonathantneal). diff --git a/docs/_sass/vendor/normalize.scss/normalize.scss b/docs/_sass/vendor/normalize.scss/normalize.scss new file mode 100755 index 00000000..ce38a4fa --- /dev/null +++ b/docs/_sass/vendor/normalize.scss/normalize.scss @@ -0,0 +1,427 @@ +/*! normalize.scss v0.1.0 | MIT License | based on git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/docs/_sass/vendor/normalize.scss/package.json b/docs/_sass/vendor/normalize.scss/package.json new file mode 100755 index 00000000..2d051c27 --- /dev/null +++ b/docs/_sass/vendor/normalize.scss/package.json @@ -0,0 +1,70 @@ +{ + "_args": [ + [ + "normalize.scss", + "/Users/pmarsceill/_projects/just-the-docs" + ] + ], + "_from": "normalize.scss@*", + "_id": "normalize.scss@0.1.0", + "_inCache": true, + "_installable": true, + "_location": "/normalize.scss", + "_nodeVersion": "0.10.32", + "_npmUser": { + "email": "alexguerrero1092@gmail.com", + "name": "alexguerrero" + }, + "_npmVersion": "2.0.2", + "_phantomChildren": {}, + "_requested": { + "name": "normalize.scss", + "raw": "normalize.scss", + "rawSpec": "", + "scope": null, + "spec": "*", + "type": "range" + }, + "_requiredBy": [ + "#DEV:/" + ], + "_resolved": "https://registry.npmjs.org/normalize.scss/-/normalize.scss-0.1.0.tgz", + "_shasum": "4a21dc25bd4c019c857785f829b658aba2a8f9ab", + "_shrinkwrap": null, + "_spec": "normalize.scss", + "_where": "/Users/pmarsceill/_projects/just-the-docs", + "author": "", + "bugs": { + "url": "https://github.com/guerrero/normalize.scss/issues" + }, + "dependencies": {}, + "description": "Normalize.scss as a node packaged module", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "4a21dc25bd4c019c857785f829b658aba2a8f9ab", + "tarball": "https://registry.npmjs.org/normalize.scss/-/normalize.scss-0.1.0.tgz" + }, + "files": [ + "normalize.scss" + ], + "gitHead": "d67d517e28615a873066438af1d4845c157c9baf", + "homepage": "https://github.com/guerrero/normalize.scss", + "license": "MIT", + "maintainers": [ + { + "name": "alexguerrero", + "email": "alexguerrero1092@gmail.com" + } + ], + "name": "normalize.scss", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git://github.com/guerrero/normalize.scss.git" + }, + "scripts": {}, + "style": "normalize.scss", + "version": "0.1.0" +} diff --git a/docs/assets/css/just-the-docs-dark.scss b/docs/assets/css/just-the-docs-dark.scss new file mode 100755 index 00000000..ac92fb15 --- /dev/null +++ b/docs/assets/css/just-the-docs-dark.scss @@ -0,0 +1,3 @@ +--- +--- +{% include css/just-the-docs.scss.liquid color_scheme="dark" %} diff --git a/docs/assets/css/just-the-docs-default.scss b/docs/assets/css/just-the-docs-default.scss new file mode 100755 index 00000000..63fde26e --- /dev/null +++ b/docs/assets/css/just-the-docs-default.scss @@ -0,0 +1,8 @@ +--- +--- +{% if site.color_scheme and site.color_scheme != "nil" %} + {% assign color_scheme = site.color_scheme %} +{% else %} + {% assign color_scheme = "light" %} +{% endif %} +{% include css/just-the-docs.scss.liquid color_scheme=color_scheme %} diff --git a/docs/assets/css/just-the-docs-light.scss b/docs/assets/css/just-the-docs-light.scss new file mode 100755 index 00000000..ac69688d --- /dev/null +++ b/docs/assets/css/just-the-docs-light.scss @@ -0,0 +1,3 @@ +--- +--- +{% include css/just-the-docs.scss.liquid color_scheme="light" %} diff --git a/docs/assets/images/search.svg b/docs/assets/images/search.svg new file mode 100755 index 00000000..421ca4df --- /dev/null +++ b/docs/assets/images/search.svg @@ -0,0 +1 @@ +Search diff --git a/docs/assets/js/just-the-docs.js b/docs/assets/js/just-the-docs.js new file mode 100755 index 00000000..c287ec08 --- /dev/null +++ b/docs/assets/js/just-the-docs.js @@ -0,0 +1,471 @@ +--- +--- +(function (jtd, undefined) { + +// Event handling + +jtd.addEvent = function(el, type, handler) { + if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); +} +jtd.removeEvent = function(el, type, handler) { + if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); +} +jtd.onReady = function(ready) { + // in case the document is already rendered + if (document.readyState!='loading') ready(); + // modern browsers + else if (document.addEventListener) document.addEventListener('DOMContentLoaded', ready); + // IE <= 8 + else document.attachEvent('onreadystatechange', function(){ + if (document.readyState=='complete') ready(); + }); +} + +// Show/hide mobile menu + +function initNav() { + jtd.addEvent(document, 'click', function(e){ + var target = e.target; + while (target && !(target.classList && target.classList.contains('nav-list-expander'))) { + target = target.parentNode; + } + if (target) { + e.preventDefault(); + target.parentNode.classList.toggle('active'); + } + }); + + const siteNav = document.getElementById('site-nav'); + const mainHeader = document.getElementById('main-header'); + const menuButton = document.getElementById('menu-button'); + + jtd.addEvent(menuButton, 'click', function(e){ + e.preventDefault(); + + if (menuButton.classList.toggle('nav-open')) { + siteNav.classList.add('nav-open'); + mainHeader.classList.add('nav-open'); + } else { + siteNav.classList.remove('nav-open'); + mainHeader.classList.remove('nav-open'); + } + }); + + {%- if site.search_enabled != false and site.search.button %} + const searchInput = document.getElementById('search-input'); + const searchButton = document.getElementById('search-button'); + + jtd.addEvent(searchButton, 'click', function(e){ + e.preventDefault(); + + mainHeader.classList.add('nav-open'); + searchInput.focus(); + }); + {%- endif %} +} + +{%- if site.search_enabled != false %} +// Site search + +function initSearch() { + var request = new XMLHttpRequest(); + request.open('GET', '{{ "assets/js/search-data.json" | absolute_url }}', true); + + request.onload = function(){ + if (request.status >= 200 && request.status < 400) { + var docs = JSON.parse(request.responseText); + + lunr.tokenizer.separator = {{ site.search.tokenizer_separator | default: site.search_tokenizer_separator | default: "/[\s\-/]+/" }} + + var index = lunr(function(){ + this.ref('id'); + this.field('title', { boost: 200 }); + this.field('content', { boost: 2 }); + {%- if site.search.rel_url != false %} + this.field('relUrl'); + {%- endif %} + this.metadataWhitelist = ['position'] + + for (var i in docs) { + this.add({ + id: i, + title: docs[i].title, + content: docs[i].content, + {%- if site.search.rel_url != false %} + relUrl: docs[i].relUrl + {%- endif %} + }); + } + }); + + searchLoaded(index, docs); + } else { + console.log('Error loading ajax request. Request status:' + request.status); + } + }; + + request.onerror = function(){ + console.log('There was a connection error'); + }; + + request.send(); +} + +function searchLoaded(index, docs) { + var index = index; + var docs = docs; + var searchInput = document.getElementById('search-input'); + var searchResults = document.getElementById('search-results'); + var mainHeader = document.getElementById('main-header'); + var currentInput; + var currentSearchIndex = 0; + + function showSearch() { + document.documentElement.classList.add('search-active'); + } + + function hideSearch() { + document.documentElement.classList.remove('search-active'); + } + + function update() { + currentSearchIndex++; + + var input = searchInput.value; + if (input === '') { + hideSearch(); + } else { + showSearch(); + // scroll search input into view, workaround for iOS Safari + window.scroll(0, -1); + setTimeout(function(){ window.scroll(0, 0); }, 0); + } + if (input === currentInput) { + return; + } + currentInput = input; + searchResults.innerHTML = ''; + if (input === '') { + return; + } + + var results = index.query(function (query) { + var tokens = lunr.tokenizer(input) + query.term(tokens, { + boost: 10 + }); + query.term(tokens, { + wildcard: lunr.Query.wildcard.TRAILING + }); + }); + + if ((results.length == 0) && (input.length > 2)) { + var tokens = lunr.tokenizer(input).filter(function(token, i) { + return token.str.length < 20; + }) + if (tokens.length > 0) { + results = index.query(function (query) { + query.term(tokens, { + editDistance: Math.round(Math.sqrt(input.length / 2 - 1)) + }); + }); + } + } + + if (results.length == 0) { + var noResultsDiv = document.createElement('div'); + noResultsDiv.classList.add('search-no-result'); + noResultsDiv.innerText = 'No results found'; + searchResults.appendChild(noResultsDiv); + + } else { + var resultsList = document.createElement('ul'); + resultsList.classList.add('search-results-list'); + searchResults.appendChild(resultsList); + + addResults(resultsList, results, 0, 10, 100, currentSearchIndex); + } + + function addResults(resultsList, results, start, batchSize, batchMillis, searchIndex) { + if (searchIndex != currentSearchIndex) { + return; + } + for (var i = start; i < (start + batchSize); i++) { + if (i == results.length) { + return; + } + addResult(resultsList, results[i]); + } + setTimeout(function() { + addResults(resultsList, results, start + batchSize, batchSize, batchMillis, searchIndex); + }, batchMillis); + } + + function addResult(resultsList, result) { + var doc = docs[result.ref]; + + var resultsListItem = document.createElement('li'); + resultsListItem.classList.add('search-results-list-item'); + resultsList.appendChild(resultsListItem); + + var resultLink = document.createElement('a'); + resultLink.classList.add('search-result'); + resultLink.setAttribute('href', doc.url); + resultsListItem.appendChild(resultLink); + + var resultTitle = document.createElement('div'); + resultTitle.classList.add('search-result-title'); + resultLink.appendChild(resultTitle); + + var resultDoc = document.createElement('div'); + resultDoc.classList.add('search-result-doc'); + resultDoc.innerHTML = ''; + resultTitle.appendChild(resultDoc); + + var resultDocTitle = document.createElement('div'); + resultDocTitle.classList.add('search-result-doc-title'); + resultDocTitle.innerHTML = doc.doc; + resultDoc.appendChild(resultDocTitle); + var resultDocOrSection = resultDocTitle; + + if (doc.doc != doc.title) { + resultDoc.classList.add('search-result-doc-parent'); + var resultSection = document.createElement('div'); + resultSection.classList.add('search-result-section'); + resultSection.innerHTML = doc.title; + resultTitle.appendChild(resultSection); + resultDocOrSection = resultSection; + } + + var metadata = result.matchData.metadata; + var titlePositions = []; + var contentPositions = []; + for (var j in metadata) { + var meta = metadata[j]; + if (meta.title) { + var positions = meta.title.position; + for (var k in positions) { + titlePositions.push(positions[k]); + } + } + if (meta.content) { + var positions = meta.content.position; + for (var k in positions) { + var position = positions[k]; + var previewStart = position[0]; + var previewEnd = position[0] + position[1]; + var ellipsesBefore = true; + var ellipsesAfter = true; + for (var k = 0; k < {{ site.search.preview_words_before | default: 5 }}; k++) { + var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2); + var nextDot = doc.content.lastIndexOf('. ', previewStart - 2); + if ((nextDot >= 0) && (nextDot > nextSpace)) { + previewStart = nextDot + 1; + ellipsesBefore = false; + break; + } + if (nextSpace < 0) { + previewStart = 0; + ellipsesBefore = false; + break; + } + previewStart = nextSpace + 1; + } + for (var k = 0; k < {{ site.search.preview_words_after | default: 10 }}; k++) { + var nextSpace = doc.content.indexOf(' ', previewEnd + 1); + var nextDot = doc.content.indexOf('. ', previewEnd + 1); + if ((nextDot >= 0) && (nextDot < nextSpace)) { + previewEnd = nextDot; + ellipsesAfter = false; + break; + } + if (nextSpace < 0) { + previewEnd = doc.content.length; + ellipsesAfter = false; + break; + } + previewEnd = nextSpace; + } + contentPositions.push({ + highlight: position, + previewStart: previewStart, previewEnd: previewEnd, + ellipsesBefore: ellipsesBefore, ellipsesAfter: ellipsesAfter + }); + } + } + } + + if (titlePositions.length > 0) { + titlePositions.sort(function(p1, p2){ return p1[0] - p2[0] }); + resultDocOrSection.innerHTML = ''; + addHighlightedText(resultDocOrSection, doc.title, 0, doc.title.length, titlePositions); + } + + if (contentPositions.length > 0) { + contentPositions.sort(function(p1, p2){ return p1.highlight[0] - p2.highlight[0] }); + var contentPosition = contentPositions[0]; + var previewPosition = { + highlight: [contentPosition.highlight], + previewStart: contentPosition.previewStart, previewEnd: contentPosition.previewEnd, + ellipsesBefore: contentPosition.ellipsesBefore, ellipsesAfter: contentPosition.ellipsesAfter + }; + var previewPositions = [previewPosition]; + for (var j = 1; j < contentPositions.length; j++) { + contentPosition = contentPositions[j]; + if (previewPosition.previewEnd < contentPosition.previewStart) { + previewPosition = { + highlight: [contentPosition.highlight], + previewStart: contentPosition.previewStart, previewEnd: contentPosition.previewEnd, + ellipsesBefore: contentPosition.ellipsesBefore, ellipsesAfter: contentPosition.ellipsesAfter + } + previewPositions.push(previewPosition); + } else { + previewPosition.highlight.push(contentPosition.highlight); + previewPosition.previewEnd = contentPosition.previewEnd; + previewPosition.ellipsesAfter = contentPosition.ellipsesAfter; + } + } + + var resultPreviews = document.createElement('div'); + resultPreviews.classList.add('search-result-previews'); + resultLink.appendChild(resultPreviews); + + var content = doc.content; + for (var j = 0; j < Math.min(previewPositions.length, {{ site.search.previews | default: 3 }}); j++) { + var position = previewPositions[j]; + + var resultPreview = document.createElement('div'); + resultPreview.classList.add('search-result-preview'); + resultPreviews.appendChild(resultPreview); + + if (position.ellipsesBefore) { + resultPreview.appendChild(document.createTextNode('... ')); + } + addHighlightedText(resultPreview, content, position.previewStart, position.previewEnd, position.highlight); + if (position.ellipsesAfter) { + resultPreview.appendChild(document.createTextNode(' ...')); + } + } + } + + {%- if site.search.rel_url != false %} + var resultRelUrl = document.createElement('span'); + resultRelUrl.classList.add('search-result-rel-url'); + resultRelUrl.innerText = doc.relUrl; + resultTitle.appendChild(resultRelUrl); + {%- endif %} + } + + function addHighlightedText(parent, text, start, end, positions) { + var index = start; + for (var i in positions) { + var position = positions[i]; + var span = document.createElement('span'); + span.innerHTML = text.substring(index, position[0]); + parent.appendChild(span); + index = position[0] + position[1]; + var highlight = document.createElement('span'); + highlight.classList.add('search-result-highlight'); + highlight.innerHTML = text.substring(position[0], index); + parent.appendChild(highlight); + } + var span = document.createElement('span'); + span.innerHTML = text.substring(index, end); + parent.appendChild(span); + } + } + + jtd.addEvent(searchInput, 'focus', function(){ + setTimeout(update, 0); + }); + + jtd.addEvent(searchInput, 'keyup', function(e){ + switch (e.keyCode) { + case 27: // When esc key is pressed, hide the results and clear the field + searchInput.value = ''; + break; + case 38: // arrow up + case 40: // arrow down + case 13: // enter + e.preventDefault(); + return; + } + update(); + }); + + jtd.addEvent(searchInput, 'keydown', function(e){ + switch (e.keyCode) { + case 38: // arrow up + e.preventDefault(); + var active = document.querySelector('.search-result.active'); + if (active) { + active.classList.remove('active'); + if (active.parentElement.previousSibling) { + var previous = active.parentElement.previousSibling.querySelector('.search-result'); + previous.classList.add('active'); + } + } + return; + case 40: // arrow down + e.preventDefault(); + var active = document.querySelector('.search-result.active'); + if (active) { + if (active.parentElement.nextSibling) { + var next = active.parentElement.nextSibling.querySelector('.search-result'); + active.classList.remove('active'); + next.classList.add('active'); + } + } else { + var next = document.querySelector('.search-result'); + if (next) { + next.classList.add('active'); + } + } + return; + case 13: // enter + e.preventDefault(); + var active = document.querySelector('.search-result.active'); + if (active) { + active.click(); + } else { + var first = document.querySelector('.search-result'); + if (first) { + first.click(); + } + } + return; + } + }); + + jtd.addEvent(document, 'click', function(e){ + if (e.target != searchInput) { + hideSearch(); + } + }); +} +{%- endif %} + +// Switch theme + +jtd.getTheme = function() { + var cssFileHref = document.querySelector('[rel="stylesheet"]').getAttribute('href'); + return cssFileHref.substring(cssFileHref.lastIndexOf('-') + 1, cssFileHref.length - 4); +} + +jtd.setTheme = function(theme) { + var cssFile = document.querySelector('[rel="stylesheet"]'); + cssFile.setAttribute('href', '{{ "assets/css/just-the-docs-" | absolute_url }}' + theme + '.css'); +} + +// Document ready + +jtd.onReady(function(){ + initNav(); + {%- if site.search_enabled != false %} + initSearch(); + {%- endif %} +}); + +})(window.jtd = window.jtd || {}); + +{% include js/custom.js %} diff --git a/docs/assets/js/vendor/lunr.min.js b/docs/assets/js/vendor/lunr.min.js new file mode 100755 index 00000000..34b279da --- /dev/null +++ b/docs/assets/js/vendor/lunr.min.js @@ -0,0 +1,6 @@ +/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.6 + * Copyright (C) 2019 Oliver Nightingale + * @license MIT + */ +!function(){var e=function(t){var r=new e.Builder;return r.pipeline.add(e.trimmer,e.stopWordFilter,e.stemmer),r.searchPipeline.add(e.stemmer),t.call(r,r),r.build()};e.version="2.3.6",e.utils={},e.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),e.utils.asString=function(e){return void 0===e||null===e?"":e.toString()},e.utils.clone=function(e){if(null===e||void 0===e)return e;for(var t=Object.create(null),r=Object.keys(e),i=0;i0){var c=e.utils.clone(r)||{};c.position=[a,l],c.index=s.length,s.push(new e.Token(i.slice(a,o),c))}a=o+1}}return s},e.tokenizer.separator=/[\s\-]+/,e.Pipeline=function(){this._stack=[]},e.Pipeline.registeredFunctions=Object.create(null),e.Pipeline.registerFunction=function(t,r){r in this.registeredFunctions&&e.utils.warn("Overwriting existing registered function: "+r),t.label=r,e.Pipeline.registeredFunctions[t.label]=t},e.Pipeline.warnIfFunctionNotRegistered=function(t){var r=t.label&&t.label in this.registeredFunctions;r||e.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",t)},e.Pipeline.load=function(t){var r=new e.Pipeline;return t.forEach(function(t){var i=e.Pipeline.registeredFunctions[t];if(!i)throw new Error("Cannot load unregistered function: "+t);r.add(i)}),r},e.Pipeline.prototype.add=function(){var t=Array.prototype.slice.call(arguments);t.forEach(function(t){e.Pipeline.warnIfFunctionNotRegistered(t),this._stack.push(t)},this)},e.Pipeline.prototype.after=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,r)},e.Pipeline.prototype.before=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");this._stack.splice(i,0,r)},e.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);t!=-1&&this._stack.splice(t,1)},e.Pipeline.prototype.run=function(e){for(var t=this._stack.length,r=0;r1&&(se&&(r=n),s!=e);)i=r-t,n=t+Math.floor(i/2),s=this.elements[2*n];return s==e?2*n:s>e?2*n:sa?l+=2:o==a&&(t+=r[u+1]*i[l+1],u+=2,l+=2);return t},e.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},e.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,r=0;t0){var o,a=s.str.charAt(0);a in s.node.edges?o=s.node.edges[a]:(o=new e.TokenSet,s.node.edges[a]=o),1==s.str.length&&(o["final"]=!0),n.push({node:o,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(0!=s.editsRemaining){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new e.TokenSet;s.node.edges["*"]=u}if(0==s.str.length&&(u["final"]=!0),n.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&n.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),1==s.str.length&&(s.node["final"]=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new e.TokenSet;s.node.edges["*"]=l}1==s.str.length&&(l["final"]=!0),n.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var c,h=s.str.charAt(0),d=s.str.charAt(1);d in s.node.edges?c=s.node.edges[d]:(c=new e.TokenSet,s.node.edges[d]=c),1==s.str.length&&(c["final"]=!0),n.push({node:c,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return i},e.TokenSet.fromString=function(t){for(var r=new e.TokenSet,i=r,n=0,s=t.length;n=e;t--){var r=this.uncheckedNodes[t],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r["char"]]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}},e.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},e.Index.prototype.search=function(t){return this.query(function(r){var i=new e.QueryParser(t,r);i.parse()})},e.Index.prototype.query=function(t){for(var r=new e.Query(this.fields),i=Object.create(null),n=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},e.Builder.prototype.k1=function(e){this._k1=e},e.Builder.prototype.add=function(t,r){var i=t[this._ref],n=Object.keys(this._fields);this._documents[i]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return e.QueryLexer.EOS;var t=this.str.charAt(this.pos);return this.pos+=1,t},e.QueryLexer.prototype.width=function(){return this.pos-this.start},e.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},e.QueryLexer.prototype.backup=function(){this.pos-=1},e.QueryLexer.prototype.acceptDigitRun=function(){var t,r;do t=this.next(),r=t.charCodeAt(0);while(r>47&&r<58);t!=e.QueryLexer.EOS&&this.backup()},e.QueryLexer.prototype.more=function(){return this.pos1&&(t.backup(),t.emit(e.QueryLexer.TERM)),t.ignore(),t.more())return e.QueryLexer.lexText},e.QueryLexer.lexEditDistance=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.EDIT_DISTANCE),e.QueryLexer.lexText},e.QueryLexer.lexBoost=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.BOOST),e.QueryLexer.lexText},e.QueryLexer.lexEOS=function(t){t.width()>0&&t.emit(e.QueryLexer.TERM)},e.QueryLexer.termSeparator=e.tokenizer.separator,e.QueryLexer.lexText=function(t){for(;;){var r=t.next();if(r==e.QueryLexer.EOS)return e.QueryLexer.lexEOS;if(92!=r.charCodeAt(0)){if(":"==r)return e.QueryLexer.lexField;if("~"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexEditDistance;if("^"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexBoost;if("+"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if("-"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if(r.match(e.QueryLexer.termSeparator))return e.QueryLexer.lexTerm}else t.escapeCharacter()}},e.QueryParser=function(t,r){this.lexer=new e.QueryLexer(t),this.query=r,this.currentClause={},this.lexemeIdx=0},e.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var t=e.QueryParser.parseClause;t;)t=t(this);return this.query},e.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},e.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},e.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},e.QueryParser.parseClause=function(t){var r=t.peekLexeme();if(void 0!=r)switch(r.type){case e.QueryLexer.PRESENCE:return e.QueryParser.parsePresence;case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(i+=" with value '"+r.str+"'"),new e.QueryParseError(i,r.start,r.end)}},e.QueryParser.parsePresence=function(t){var r=t.consumeLexeme();if(void 0!=r){switch(r.str){case"-":t.currentClause.presence=e.Query.presence.PROHIBITED;break;case"+":t.currentClause.presence=e.Query.presence.REQUIRED;break;default:var i="unrecognised presence operator'"+r.str+"'";throw new e.QueryParseError(i,r.start,r.end)}var n=t.peekLexeme();if(void 0==n){var i="expecting term or field, found nothing";throw new e.QueryParseError(i,r.start,r.end)}switch(n.type){case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expecting term or field, found '"+n.type+"'";throw new e.QueryParseError(i,n.start,n.end)}}},e.QueryParser.parseField=function(t){var r=t.consumeLexeme();if(void 0!=r){if(t.query.allFields.indexOf(r.str)==-1){var i=t.query.allFields.map(function(e){return"'"+e+"'"}).join(", "),n="unrecognised field '"+r.str+"', possible fields: "+i;throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.fields=[r.str];var s=t.peekLexeme();if(void 0==s){var n="expecting term, found nothing";throw new e.QueryParseError(n,r.start,r.end)}switch(s.type){case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var n="expecting term, found '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseTerm=function(t){var r=t.consumeLexeme();if(void 0!=r){t.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(t.currentClause.usePipeline=!1);var i=t.peekLexeme();if(void 0==i)return void t.nextClause();switch(i.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+i.type+"'";throw new e.QueryParseError(n,i.start,i.end)}}},e.QueryParser.parseEditDistance=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="edit distance must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.editDistance=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseBoost=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="boost must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.boost=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.lunr=t()}(this,function(){return e})}(); diff --git a/docs/bin/just-the-docs b/docs/bin/just-the-docs new file mode 100755 index 00000000..5a622903 --- /dev/null +++ b/docs/bin/just-the-docs @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby + +gem_dir = File.expand_path("..",File.dirname(__FILE__)) +$LOAD_PATH.unshift gem_dir # Look in gem directory for resources first. +exec_type = ARGV[0] + +if exec_type == 'rake' then + require 'rake' + require 'pp' + pwd=Dir.pwd + Dir.chdir(gem_dir) # We'll load rakefile from the gem's dir. + Rake.application.init + Rake.application.load_rakefile + Dir.chdir(pwd) # Revert to original pwd for any path args passed to task. + Rake.application.invoke_task(ARGV[1]) +end From 477437f3894721454c93c9b39cd281b4742d0a8b Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:21:09 -0700 Subject: [PATCH 25/61] Custom styles --- docs/_sass/color_schemes/dictu.scss | 2 ++ docs/_sass/custom/custom.scss | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 docs/_sass/color_schemes/dictu.scss create mode 100755 docs/_sass/custom/custom.scss diff --git a/docs/_sass/color_schemes/dictu.scss b/docs/_sass/color_schemes/dictu.scss new file mode 100644 index 00000000..e0e45d32 --- /dev/null +++ b/docs/_sass/color_schemes/dictu.scss @@ -0,0 +1,2 @@ +$link-color: #000000; +$btn-primary-color: #808080; \ No newline at end of file diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss new file mode 100755 index 00000000..361dcaff --- /dev/null +++ b/docs/_sass/custom/custom.scss @@ -0,0 +1,19 @@ +body { + margin-top: 3px; + + &:before { + content: ''; + width: 100%; + height: 3px; + background-image: linear-gradient(to right, #3b8ff6, #6eff53, #fd9122, #fd642f, #f192e7, #503873); + position: fixed; + top: 0; + z-index: 100000; + } +} + +.site-footer { display: none; } + +.site-logo { + background-size: auto 20px; +} \ No newline at end of file From 4783faeba44880ca4bf7640d2406a4f86f6fa0d1 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:21:25 -0700 Subject: [PATCH 26/61] Add logo variation --- docs/assets/images/dictu-logo/dictu-wordmark.svg | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/assets/images/dictu-logo/dictu-wordmark.svg diff --git a/docs/assets/images/dictu-logo/dictu-wordmark.svg b/docs/assets/images/dictu-logo/dictu-wordmark.svg new file mode 100644 index 00000000..a7acc505 --- /dev/null +++ b/docs/assets/images/dictu-logo/dictu-wordmark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + From dde8bc5d83682db9b06f6031d97ac68b26a56765 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:21:39 -0700 Subject: [PATCH 27/61] Rewrite getting started --- docs/docs/getting-started.md | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md index 2789e7c6..71428e7c 100644 --- a/docs/docs/getting-started.md +++ b/docs/docs/getting-started.md @@ -16,33 +16,26 @@ nav_order: 2 --- ## Hello World! -We saw on the last page how to open the REPL and execute code on there, now lets create a Dictu file -and execute that. For this step, i'm going to create an empty file via the command line, this -is to leave it "editor agnostic". +We've already learned how to enter the REPL and run code there. Now, let's create a Dictu file and execute it. Open your favorite code editor, and create a new file with a `.du` extension. If you're new to programming or aren't sure which editor to use, [Visual Studio Code](https://code.visualstudio.com/) (with the [Dictu extension](https://github.com/dictu-lang/DictuVSC)), [Atom](https://atom.io/), or [Sublime Text](https://www.sublimetext.com/) are all fantastic (and free) choices. -```bash -$ touch new_dictu.du -``` -At this point, i'm going to assume you have opened `new_dictu.du` in whichever editor you use. +We're going to call our file `hello-world.du`: ```js -//new_dictu.du -print("Hello World!"); +print("Hello, World!"); ``` -And now lets execute our file. +That's all we'll put in it for now. Let's execute our file. It's just like entering the REPL, except we add the path to out file after `./dictu`. ```bash $ ./dictu new_dictu.du Hello World! ``` -As you see, Hello World! is printed to the screen. You have just created your first Dictu -program, now onto bigger and better things! +As you see, `Hello, World!` is printed to the screen. You have just created your first Dictu program, now onto bigger and better things! ## REPL -The REPL is a language shell, allowing you to run code on the fly via your terminal. This is very useful for debugging, or small little checks you may want to perform. When you enter the REPL, there is a magic variable `_` which stores the last returned value (nil excluded). +The REPL is a language shell, allowing you to run code on the fly via your terminal. This is very useful for debugging, or small little checks you may want to perform. When you enter the REPL, there is a magic variable `_` which stores the last returned value (`nil` excluded). ``` Dictu Version: {{ site.version }} @@ -55,17 +48,14 @@ Dictu Version: {{ site.version }} ## Comments -Comments are an important part of any language, and here in Dictu, this is no exception. Comment syntax should be very familiar to you as it's the same in a variety of languages. +It's always important to comment your code! Comments are used to explain what your code does. Dictu's syntax will be familiar to any programmer. ```js // This is a single line comment /* -this -is -a -multiline -comment +This is a +multiline comment */ ``` From 0f528b7b14f9efd945d5d220fe3335a9707c9f1a Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:21:49 -0700 Subject: [PATCH 28/61] Rewrite variables and data types --- docs/docs/variables.md | 118 +++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/docs/docs/variables.md b/docs/docs/variables.md index 5097f922..e0a75ad6 100644 --- a/docs/docs/variables.md +++ b/docs/docs/variables.md @@ -1,10 +1,10 @@ --- layout: default -title: Variables +title: Variables and types nav_order: 3 --- -# Variables +# Variables and types {: .no_toc } ## Table of contents @@ -16,98 +16,91 @@ nav_order: 3 --- ## Data types -| Type | Values | -|:-------------|:----------------------------------------------------------------------------------------------------------| -| Number | This includes both integers and floats.

10, 10.5 | -| String | "Hello World!", 'Hello World!' | -| Boolean | true, false | -| List | Lists can contain any value.

[1, 2, "hi", true, nil] | -| Dictionary | Dictionaries are key value pairs. Keys need to be of type string, nil, boolean or number.

{"key1": 10, 2: "two", true: "true", nil: "nil"} | -| Set | Sets are an unordered collection of unique hashable values. -| nil | nil | +| Type | Example | Note | +| --- | --- | --- | +| String | ‘foo’, “bar” | You can use single or double quotes to represent strings in Dictu. | +| Number | 100, 100.5 | This data type includes both integers (whole numbers) and floats (numbers with decimals). | +| Boolean | true, false | | +| List | [1, 2, ‘hi’, true, nil] | Lists can contain any data type or combination of data types. | +| Dictionary | {“key1”: 10, 2: “two”, true: “true”, nil: “nil”} | Dictionaries have key-value pairs, like a dictionary (Word: Definition). Values can be any of the data types above except lists. | +| Set | | Sets are unordered collections of unique hashable values. | +| Nil | nil | Don’t confuse `nil` with `null`! While they mean the same thing in the English language, and the latter is more common in programming, `null` has no significance in Dictu. | ## Declaring a variable -Syntax: -```js +```cs var someNumber = 10; var someString = "hello"; var someOtherString = 'hello'; var someBoolean = true; var someFalseBoolean = false; var someNilValue = nil; -var someOtherNilValue; // Variables declared without a value are set to nil -var someList = [1, 2, "hi", 'hi', nil, true, false]; // Lists can hold any value +var someOtherNilValue; // This variable is equal to nil +var someList = [1, 2, "hi", 'hi', nil, true, false]; var someDict = {"key": 10, "key1": true, 2: [1, "2", false], true: {"1": 2}}; var someSet = set(); ``` +Variable names can start with an uppercase or lowercase letter or an underscore. The rest of the characters can be letters, digits, or underscores. The value must be another defined variable or a valid data type. Variables cannot be named several reserved terms: `import`, `true`, `false`, `nil`, `const`, `var`, and more. -To define a variable in Dictu the syntax is as follows `var = ;` where identifier -is defined as such `[a-zA-Z_]+[a-zA-Z0-9_]*` and value is a valid datatype. - -Once a variable has been defined, `var` is no longer needed to update the value of the variable. - -E.g -```js +Once a variable has been defined, `var` is no longer needed to update the value of the variable: +```cs var someNumber = 10; -someNumber = someNumber + 1; +someNumber = someNumber + 13; ``` -Variables are also allowed to change their type at runtime. - -E.g -```js +Variables can also change their data type without being redclared with `var`: +```cs var someVariable = 10; -someVariable = "Some text"; // Is perfectly valid +someVariable = "A string"; // Perfectly valid! ``` You can also define multiple variables with a single statement. - -```js -var a, b = 10, c = "hello!"; -print(a, b, c); // nil, 10, 'hello!' +```cs +var a, + b = 10, + c = "Hello!"; +print(a, b, c); // nil, 10, 'Hello!' ``` ### Constants -Constants are like variables however they differ in that they are read-only. Once a constant has been set its value -is unable to be changed. Constants also must have a value specified when they are declared. - -Constants have a set value, however the value it holds may be mutable, for example a list, if this is the case -the mutable type ***can*** still be modified. +Constants are like variables, however they are read-only. Once a constant has been declared, its value cannot be changed later in the program. Constant names must follow the same rules as variable names. -```js +```cs const x = 10; -x = 10; // [line 1] Error at '=': Cannot assign to a constant. +x = 15; // [line 1] Error at '=': Cannot assign to a constant. print(x); // 10 - -const y = 10, z = 20; // Both y and z are constants ``` -## Casting +Like variables, multiple constants can be declared at once: +```cs +const y = 10, + z = 20; // Both y and z are constants +print(y, z); // 10, 20 +``` -### value.toString() +## Type casting -You can convert values into strings with the toString() method. +You can convert between data types using several built-in methods. -```js -true.toString(); -nil.toString(); -1.toString(); -someDict.toString(); -someList.toString(); -someSet.toString(); +### value.toString(); +You can convert values into strings with the toString() method. This method can be called on variables, constants, and directly on values, as shown below. +```cs +true.toString(); // 'true' +nil.toString(); // 'nil' +1.toString(); // '1' +{"key": "value"}.toString(); // {"key": "value"} +[1,2,3].toString(); // '[1, 2, 3]' +set().toString(); // '{}' ``` -### value.toBool() - -You can convert values into booleans with the toBool method. This is based on whether the -value is "truthy" or not. A "truthy" value is a value which has a length greater than 0 -or is not 0 when checking number types. `nil` is always false. +### value.toBool(); +You can convert values into booleans with the `toBool()` method. Dictu will decide whether a value is "truthy" or not. A "truthy" value is longer than 0 or is not 0 when checking number types. `nil` is always false. -```js +```cs "".toBool(); // false +" ".toBool(); // true "test".toBool(); // true "false".toBool(); // true @@ -118,3 +111,14 @@ or is not 0 when checking number types. `nil` is always false. [1].toBool(); // true [[]].toBool(); // true ``` + +### value.toNumber(); + +The `toNumber()` method is only for converting a string to a number. This method has a few strange caveats (see the examples below). + +```cs +"123".toNumber(); // 123 +" 123".toNumber(); // 123 +"123 ".toNumber(); // nil +"Hello".toNumber(); // nil +``` \ No newline at end of file From cc00d9ee293fed74217d3c1df43c224832a6fd81 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sat, 3 Oct 2020 23:21:56 -0700 Subject: [PATCH 29/61] Add favicon (SEO) --- docs/favicon.ico | Bin 0 -> 109812 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/favicon.ico diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8799d238669436db6d41921828b9ae31d8fc6bdc GIT binary patch literal 109812 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 Date: Sat, 3 Oct 2020 23:22:04 -0700 Subject: [PATCH 30/61] Rewrite index page --- docs/index.md | 55 +++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/docs/index.md b/docs/index.md index 3f7dd763..ef2cccd5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,27 +1,30 @@ --- layout: default -title: Home +title: Welcome nav_order: 1 -description: "Just the Docs is a responsive Jekyll theme with built-in search that is easily customizable and hosted on GitHub Pages." permalink: / --- -# Dictu - {{ site.version }} +# Dictu v{{ site.version }} +{: .fs-9 } -### What is Dictu? +Dictu is a simple, dynamically typed programming language. +{: .fs-6 .fw-300 } + +[Install in 30 Seconds](#installing-dictu){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } [View on GitHub](https://github.com/dictu-lang/Dictu){: .btn .fs-5 .mb-4 .mb-md-0 } -Dictu is a very small, and simple dynamically typed programming language originally stemming from -the [craftinginterpreters tutorial](http://www.craftinginterpreters.com/contents.html). Since then Dictu -builds upon the concepts within the book, adding more features to the language. +```cs +import HTTP; +import JSON; -_Dictu stands for simplistic in Latin. This is the aim of the language, to be as simplistic -as humanely possible._ +var data = HTTP.get('https://api.coindesk.com/v1/bpi/currentprice.json'); +data = JSON.parse( data['content'] ); +print( '$' + data['bpi']['USD']['rate'] + ' per BTC' ); // $10,577.70 per BTC +``` -### About the project +Dictu is a very small, simple, and dynamically typed programming language inspired by a [book by Robert Nystrom](http://www.craftinginterpreters.com/contents.html). Dictu builds upon the concepts within the book and adds more features to the language. -Dictu is a small language created to learn more about how programming languages are created -and learn how features used everyday within other languages are implemented to gain a better -understanding. +Dictu means simplistic in Latin. This is the aim of the language: to be as simplistic, organized, and logical as humanly possible. {: .fs-6 .fw-300 } @@ -29,31 +32,31 @@ understanding. ## Installing Dictu +All it takes is three lines! Fire up a terminal and copy the following, one by one (without the $). + ```bash -$ git clone https://github.com/Jason2605/Dictu.git +$ git clone https://github.com/dictu-lang/Dictu.git $ cd Dictu $ make dictu ``` -Lets ensure everything went as planned by opening the Dictu REPL. +Let's make sure that everything went as planned by entering the Dictu REPL. ```bash $ ./dictu ``` -You should then be able to run dictu code in here! + +You should be able to run Dictu code here! REPL stands for “read evaluate print loop” and it allows you to receive instantaneous feedback about your code. + ``` Dictu Version: {{ site.version }} ->>> print("Hello World!"); +>>> print("Hello, World!"); ``` -When you're done playing around with the REPL, use CTRL + C to close it. - -### Contributing -I want to make the Dictu environment as friendly, and as welcoming as possible so [pull requests](https://github.com/Jason2605/Dictu/pulls) -are massively encouraged, be that the tiniest typo error in some documentation, or a new feature -within the language itself, both will be massively appreciated! However pull requests don't have to be -the only contribution to the growth of Dictu, you could, [open issues](https://github.com/Jason2605/Dictu/issues), star the repo, or even tell people that Dictu is great! +Use `Control + C` to exit the REPL when you're finished. -### License +## Contributing +We want to make the Dictu community as friendly and welcoming as possible, so [pull requests](https://github.com/dictu-lang/Dictu/pulls) are encoraged. Any contribution, from the smallest typo in the documentation to a new feature in the language itself, is greatly appreciated! -Dictu is licensed under the [MIT license](https://github.com/Jason2605/Dictu/blob/master/LICENSE). +## License +Dictu is under the [MIT license](https://github.com/dictu-lang/Dictu/blob/master/LICENSE). \ No newline at end of file From bb3efa90c29c24730667a2b9a027f7ecbefac481 Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sun, 4 Oct 2020 08:32:56 -0700 Subject: [PATCH 31/61] Add Random docs --- docs/docs/random.md | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/docs/random.md diff --git a/docs/docs/random.md b/docs/docs/random.md new file mode 100644 index 00000000..7b3ce179 --- /dev/null +++ b/docs/docs/random.md @@ -0,0 +1,52 @@ +--- +layout: default +title: Random +nav_order: 20 +--- + +# Random +{: .no_toc } + +## Table of contents +{: .no_toc .text-delta } + +1. TOC +{:toc} + +--- + +## Random +To make use of the Random module an import is required. + +```js +import Random; +``` + +### Random.random() + +Return a random float between 0 and 1. + +```js +Random.random(); // 0.314 +Random.random(); // 0.271 +``` + +### Random.range(lowest, highest) + +Returns a random integer between the lowest and highest inputes + +```js +Random.range(1, 5) // 2 +Random.range(1, 5) // 4 +Random.range(0, 2) // 1 +``` + +### Random.select(iterable) + +Returns a value randomly selected from the list + +```js +Random.select([2, 4, 6]) // 6 +Random.select([2, 4, 6]) // 2 +Random.select(["a", "b", "c"]) // "c" +``` From f4e85fd47fa5f1ef7fb52423c72dbbf00c1f93a6 Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sun, 4 Oct 2020 08:33:20 -0700 Subject: [PATCH 32/61] Fix bug in nav_order of sockets docs --- docs/docs/sockets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/sockets.md b/docs/docs/sockets.md index 05a2513b..ccf4dee0 100644 --- a/docs/docs/sockets.md +++ b/docs/docs/sockets.md @@ -1,7 +1,7 @@ --- layout: default title: Socket -nav_order: 18 +nav_order: 19 --- # Socket From e3eaa509b568017e0ab819bb4aa4f3157d5febdc Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sun, 4 Oct 2020 08:56:55 -0700 Subject: [PATCH 33/61] Change Random.random() to return a float between 0 and 1; Seed PRNG with time(NULL) --- c/optionals/random.c | 45 +++++++++++++++++++++++++++++------------- c/optionals/random.h | 1 + tests/random/random.du | 14 ++----------- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/c/optionals/random.c b/c/optionals/random.c index 0d7caba5..ae9da8ad 100644 --- a/c/optionals/random.c +++ b/c/optionals/random.c @@ -1,24 +1,33 @@ #include "random.h" -static Value randomRandom(VM *vm, int argCount, Value *args) { +static Value randomRandom(VM *vm, int argCount, Value *args) +{ UNUSED(args); - if (argCount > 0) { + if (argCount > 0) + { runtimeError(vm, "random() takes 0 arguments (%d given)", argCount); return EMPTY_VAL; } - return NUMBER_VAL(rand() % 2); + + int high = 1; + int low = 0; + double random_double = ((double)rand() * (high - low)) / (double)RAND_MAX + low; + return NUMBER_VAL(random_double); } -static Value randomRange(VM *vm, int argCount, Value *args) { - if (argCount != 2) { +static Value randomRange(VM *vm, int argCount, Value *args) +{ + if (argCount != 2) + { runtimeError(vm, "range() takes 2 arguments (%0d given)", argCount); return EMPTY_VAL; } - if (!IS_NUMBER(args[0]) || !IS_NUMBER(args[1])) { + if (!IS_NUMBER(args[0]) || !IS_NUMBER(args[1])) + { runtimeError(vm, "range() arguments must be numbers"); return EMPTY_VAL; - } + } int upper = AS_NUMBER(args[1]); int lower = AS_NUMBER(args[0]); @@ -26,24 +35,29 @@ static Value randomRange(VM *vm, int argCount, Value *args) { return NUMBER_VAL(random_val); } -static Value randomSelect(VM *vm, int argCount, Value *args) { - if (argCount == 0) { +static Value randomSelect(VM *vm, int argCount, Value *args) +{ + if (argCount == 0) + { runtimeError(vm, "select() takes one argument (%0d provided)", argCount); return EMPTY_VAL; } - if (!IS_LIST(args[0])) { + if (!IS_LIST(args[0])) + { runtimeError(vm, "select() argument must be a list"); - return EMPTY_VAL; + return EMPTY_VAL; } ObjList *list = AS_LIST(args[0]); argCount = list->values.count; args = list->values.values; - for (int i = 0; i < argCount; ++i) { + for (int i = 0; i < argCount; ++i) + { Value value = args[i]; - if (!IS_NUMBER(value)) { + if (!IS_NUMBER(value)) + { runtimeError(vm, "A non-number value passed to select()"); return EMPTY_VAL; } @@ -53,12 +67,15 @@ static Value randomSelect(VM *vm, int argCount, Value *args) { return args[index]; } -ObjModule *createRandomClass(VM *vm) { +ObjModule *createRandomClass(VM *vm) +{ ObjString *name = copyString(vm, "Random", 6); push(vm, OBJ_VAL(name)); ObjModule *module = newModule(vm, name); push(vm, OBJ_VAL(module)); + srand(time(NULL)); + /** * Define Random methods */ diff --git a/c/optionals/random.h b/c/optionals/random.h index a85d6f09..be86105e 100644 --- a/c/optionals/random.h +++ b/c/optionals/random.h @@ -2,6 +2,7 @@ #define dictu_random_h #include +#include #include "optionals.h" #include "../vm.h" diff --git a/tests/random/random.du b/tests/random/random.du index c4080993..b3975cc0 100644 --- a/tests/random/random.du +++ b/tests/random/random.du @@ -7,18 +7,8 @@ import Random; -var histogram = {0: 0, 1: 0}; var num_randomizations = 100; -var percent_error_threshold = 0.05; for (var i = 0; i < num_randomizations; ++i) { - histogram[Random.random()] += 1; -} - -var exp_percent = 0.5; -var min_percent = exp_percent - percent_error_threshold; -var max_percent = exp_percent + percent_error_threshold; -for (var i = 0; i < histogram.len(); ++i) { - var percent_of_i = histogram[i] / num_randomizations; - assert(min_percent <= percent_of_i); - assert(percent_of_i <= max_percent); + assert(Random.random() >= 0); + assert(Random.random() <= 1); } From 9bcaab9c0e06727fee6dc9f002b88acc1725f5af Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Sun, 4 Oct 2020 17:15:18 +0100 Subject: [PATCH 34/61] Update random lib documentation --- docs/docs/random.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/docs/random.md b/docs/docs/random.md index 7b3ce179..34ea0a35 100644 --- a/docs/docs/random.md +++ b/docs/docs/random.md @@ -18,6 +18,8 @@ nav_order: 20 ## Random To make use of the Random module an import is required. +**Note:** This is not cryptographically secure and should not be used for such purposes. + ```js import Random; ``` @@ -31,9 +33,9 @@ Random.random(); // 0.314 Random.random(); // 0.271 ``` -### Random.range(lowest, highest) +### Random.range(number: lowest, number: highest) -Returns a random integer between the lowest and highest inputes +Returns a random integer between the lowest and highest inputs. ```js Random.range(1, 5) // 2 @@ -43,7 +45,7 @@ Random.range(0, 2) // 1 ### Random.select(iterable) -Returns a value randomly selected from the list +Returns a value randomly selected from the list. ```js Random.select([2, 4, 6]) // 6 From 7bc91e22beecb524bb0717c5bc40f16d896f1695 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sun, 4 Oct 2020 09:48:17 -0700 Subject: [PATCH 35/61] Added dark mode --- docs/_includes/head.html | 83 ++++++++++++++++++++++++----------- docs/_sass/custom/custom.scss | 15 +++++++ 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/docs/_includes/head.html b/docs/_includes/head.html index 149e53d1..585d8147 100755 --- a/docs/_includes/head.html +++ b/docs/_includes/head.html @@ -1,29 +1,60 @@ - - - - - + + + + + + + + + + + + {{ page.title }} - {{ site.title }} + - {{ page.title }} - {{ site.title }} - + - - {% endif %} - - {% if site.search_enabled != nil %} - - {% endif %} - - - - \ No newline at end of file + document.documentElement.classList.add('dark-mode'); + + let oldLink = document.getElementById('favicon'); + let link = document.createElement('link'); + link.id = 'favicon'; + link.rel = 'shortcut icon'; + link.href = '{{ "/assets/favicon-dark.png" | absolute_url }}'; + + if (oldLink) { + document.head.removeChild(oldLink); + } + document.head.appendChild(link); + } + + })() + + + {% if site.ga_tracking != nil %} + + + + {% endif %} + + {% if site.search_enabled != nil %} + + {% endif %} + + + + \ No newline at end of file diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss index 361dcaff..b4769b09 100755 --- a/docs/_sass/custom/custom.scss +++ b/docs/_sass/custom/custom.scss @@ -16,4 +16,19 @@ body { .site-logo { background-size: auto 20px; +} + +.dark-mode { + .site-logo { + filter: invert(1); + } + + a { + color: #ffffff; + } + + .btn.btn-primary { + background-color: #767676; + background-image: linear-gradient(#858585, #767676); + } } \ No newline at end of file From 43a3bd6c0d563915da6c14cc24e6778bfc23fe6a Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Sun, 4 Oct 2020 19:00:12 +0100 Subject: [PATCH 36/61] Update the website description --- docs/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_config.yml b/docs/_config.yml index e0ce9f2d..cebd9b32 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,6 +1,6 @@ title: Dictu description: >- - Dictu is a very simple dynamically typed programming language built upon the craftinginterpreters tutorial. + Dictu is a very small and simple dynamically typed programming language. color_scheme: "dictu" # Custom theme logo: "/assets/images/dictu-logo/dictu-wordmark.svg" From e3645056d6bce96e792ee66a2f4a62f2b6542e44 Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sun, 4 Oct 2020 11:26:55 -0700 Subject: [PATCH 37/61] Add Path.listdir() method --- c/optionals/path.c | 38 +++++++++++++++++++++++++++++++++ c/optionals/path.h | 1 + docs/docs/path.md | 9 ++++++++ tests/path/listdir.du | 16 ++++++++++++++ tests/path/test_dir/test_file_1 | 0 tests/path/test_dir/test_file_2 | 0 tests/path/test_dir/test_file_3 | 0 7 files changed, 64 insertions(+) create mode 100644 tests/path/listdir.du create mode 100644 tests/path/test_dir/test_file_1 create mode 100644 tests/path/test_dir/test_file_2 create mode 100644 tests/path/test_dir/test_file_3 diff --git a/c/optionals/path.c b/c/optionals/path.c index 1db8e8fb..bda87347 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -62,6 +62,43 @@ static Value isdirNative(VM *vm, int argCount, Value *args) { } +static Value listdirNative(VM *vm, int argCount, Value *args) { + if (argCount != 1) { + runtimeError(vm, "listdir() takes 1 argument (%d given)", argCount); + return EMPTY_VAL; + } + + if (!IS_STRING(args[0])) { + runtimeError(vm, "listdir() argument must be a string"); + return EMPTY_VAL; + } + + ObjList *dir_contents = initList(vm); + push(vm, OBJ_VAL(dir_contents)); + char *path = AS_CSTRING(args[0]); + struct dirent *dir; + DIR *d; + d = opendir(path); + if (d) { + while ((dir = readdir(d)) != NULL) { + char *inode_name = dir->d_name; + if (strcmp(inode_name, ".") == 0 || strcmp(inode_name, "..") == 0) + continue; + Value inode_value = OBJ_VAL(copyString(vm, inode_name, strlen(inode_name))); + push(vm, inode_value); + writeValueArray(vm, &dir_contents->values, inode_value); + pop(vm); + } + } else { + runtimeError(vm, "%s is not a path!", path); + return EMPTY_VAL; + } + + pop(vm); + + return OBJ_VAL(dir_contents); +} + static Value basenameNative(VM *vm, int argCount, Value *args) { if (argCount != 1) { runtimeError(vm, "basename() takes 1 argument (%d given)", argCount); @@ -210,6 +247,7 @@ ObjModule *createPathClass(VM *vm) { defineNative(vm, &module->values, "dirname", dirnameNative); defineNative(vm, &module->values, "exists", existsNative); defineNative(vm, &module->values, "isdir", isdirNative); + defineNative(vm, &module->values, "listdir", listdirNative); defineNativeProperty(vm, &module->values, "delimiter", OBJ_VAL( copyString(vm, PATH_DELIMITER_AS_STRING, PATH_DELIMITER_STRLEN))); diff --git a/c/optionals/path.h b/c/optionals/path.h index 12ac6a41..c706e3cd 100644 --- a/c/optionals/path.h +++ b/c/optionals/path.h @@ -3,6 +3,7 @@ #include #include +#include #include #ifndef PATH_MAX diff --git a/docs/docs/path.md b/docs/docs/path.md index e4250f3b..2a2add7d 100644 --- a/docs/docs/path.md +++ b/docs/docs/path.md @@ -103,3 +103,12 @@ Checks whether a given path points to a directory or not. Path.isdir("/usr/bin/"); //true ``` +### Path.listdir(string) + +Returns a list of strings containing the contents of the input path. + +**Note:** This function does not guarantee any ordering of the returned list. + +```js +Path.listdir("/"); // ["bin", "dev", "home", "lib", ...] +``` diff --git a/tests/path/listdir.du b/tests/path/listdir.du new file mode 100644 index 00000000..d744caee --- /dev/null +++ b/tests/path/listdir.du @@ -0,0 +1,16 @@ +/** + * dirname.du + * + * Testing Path.listdir() + * + */ +import Path; + +var dir_contents = Path.listdir("tests/path/test_dir"); +var exp_dir_contents = ["test_file_1", "test_file_2", "test_file_3"]; + +for (var i = 0; i < exp_dir_contents.len(); ++i) { + var exp_inode = exp_dir_contents[i]; + assert(dir_contents.contains(exp_inode)); + exp_dir_contents.remove(exp_inode); +} diff --git a/tests/path/test_dir/test_file_1 b/tests/path/test_dir/test_file_1 new file mode 100644 index 00000000..e69de29b diff --git a/tests/path/test_dir/test_file_2 b/tests/path/test_dir/test_file_2 new file mode 100644 index 00000000..e69de29b diff --git a/tests/path/test_dir/test_file_3 b/tests/path/test_dir/test_file_3 new file mode 100644 index 00000000..e69de29b From cf105a50f27cb35f4fcc36b6c7afefdd9700a27a Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Sun, 4 Oct 2020 13:37:15 -0700 Subject: [PATCH 38/61] Fix quotes for C# formatting --- docs/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index ef2cccd5..2655ed6e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,9 +17,9 @@ Dictu is a simple, dynamically typed programming language. import HTTP; import JSON; -var data = HTTP.get('https://api.coindesk.com/v1/bpi/currentprice.json'); -data = JSON.parse( data['content'] ); -print( '$' + data['bpi']['USD']['rate'] + ' per BTC' ); // $10,577.70 per BTC +var data = HTTP.get("https://api.coindesk.com/v1/bpi/currentprice.json"); +data = JSON.parse( data["content"] ); +print( "$" + data["bpi"]["USD"]["rate"] + " per BTC" ); // $10,577.70 per BTC ``` Dictu is a very small, simple, and dynamically typed programming language inspired by a [book by Robert Nystrom](http://www.craftinginterpreters.com/contents.html). Dictu builds upon the concepts within the book and adds more features to the language. From ccedc10b97ee544b7b0d0e508fa563fc0bbcd219 Mon Sep 17 00:00:00 2001 From: The Great Cookie Machine <39784551+TheGreatCookieMachine@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:44:25 -0700 Subject: [PATCH 39/61] Fix Clang and MSVC warnings and refine CMakeLists --- CMakeLists.txt | 15 ++++++++++++--- c/optionals/system.c | 6 ++++++ c/optionals/system.h | 2 +- c/vm.c | 8 ++++++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db86dd18..554ab734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,13 +28,22 @@ if(WIN32) # ws2_32 is required for winsock2.h to work correctly list(APPEND libraries ws2_32) else() -list(APPEND libraries m) + list(APPEND libraries m) endif() if(MSVC) - add_compile_options() + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + set(CMAKE_C_FLAGS "/WX /W1") + set(CMAKE_C_FLAGS_DEBUG "/Zi") + set(CMAKE_C_FLAGS_RELEASE "/O2") else() - add_compile_options(-Wall -Wextra -Werror -Wshadow -Wunused-function -Wunused-macros) + set(CMAKE_C_FLAGS "-Wall -Wextra -Werror -Wshadow -Wunused-function -Wunused-macros") + set(CMAKE_C_FLAGS_DEBUG "-O0 -g") + set(CMAKE_C_FLAGS_RELEASE "-O3 -flto") +endif() + +if(CMAKE_BUILD_TYPE MATCHES Debug) + add_compile_definitions(DEBUG DEBUG_STRESS_GC DEBUG_FINAL_MEM) endif() add_executable(${PROJECT_NAME} ${sources} ${headers}) diff --git a/c/optionals/system.c b/c/optionals/system.c index b85b8204..88f66485 100644 --- a/c/optionals/system.c +++ b/c/optionals/system.c @@ -1,5 +1,11 @@ #include "system.h" +#ifdef _WIN32 +#define rmdir(DIRNAME) _rmdir(DIRNAME) +#define chdir(DIRNAME) _chdir(DIRNAME) +#define getcwd(BUFFER, MAXLEN) _getcwd(BUFFER, MAXLEN) +#endif + #ifndef _WIN32 static Value getgidNative(VM *vm, int argCount, Value *args) { UNUSED(args); diff --git a/c/optionals/system.h b/c/optionals/system.h index 3c271294..47d0f30b 100644 --- a/c/optionals/system.h +++ b/c/optionals/system.h @@ -11,7 +11,7 @@ #include "../windowsapi.h" #include #define REMOVE remove -#define MKDIR(d, m) ((void)m, mkdir(d)) +#define MKDIR(d, m) ((void)m, _mkdir(d)) #else #include #include diff --git a/c/vm.c b/c/vm.c index 7d207a2f..19301a5c 100644 --- a/c/vm.c +++ b/c/vm.c @@ -170,13 +170,17 @@ void freeVM(VM *vm) { freeTable(vm, &vm->instanceMethods); freeTable(vm, &vm->socketMethods); FREE_ARRAY(vm, CallFrame, vm->frames, vm->frameCapacity); - FREE_ARRAY(vm, const char*, vm->scriptNames, vm->scriptNameCapacity); + FREE_ARRAY(vm, const char*, (char**)vm->scriptNames, vm->scriptNameCapacity); vm->initString = NULL; vm->replVar = NULL; freeObjects(vm); #if defined(DEBUG_TRACE_MEM) || defined(DEBUG_FINAL_MEM) +#ifdef __MINGW32__ + printf("Total memory usage: %lu\n", (unsigned long)vm->bytesAllocated); +#else printf("Total memory usage: %zu\n", vm->bytesAllocated); +#endif #endif free(vm); @@ -1108,7 +1112,7 @@ static InterpretResult run(VM *vm) { if (vm->scriptNameCapacity < vm->scriptNameCount + 2) { int oldCapacity = vm->scriptNameCapacity; vm->scriptNameCapacity = GROW_CAPACITY(oldCapacity); - vm->scriptNames = GROW_ARRAY(vm, vm->scriptNames, const char*, + vm->scriptNames = GROW_ARRAY(vm, (char**)vm->scriptNames, const char*, oldCapacity, vm->scriptNameCapacity); } From 035a95d4dfcdca40b2e54029ecfa5f9bb31c3997 Mon Sep 17 00:00:00 2001 From: Sean McLoughlin Date: Sun, 4 Oct 2020 15:06:19 -0700 Subject: [PATCH 40/61] Change Path.listdir() to default to cwd with no params --- c/optionals/path.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/c/optionals/path.c b/c/optionals/path.c index bda87347..864d0a27 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -63,19 +63,24 @@ static Value isdirNative(VM *vm, int argCount, Value *args) { } static Value listdirNative(VM *vm, int argCount, Value *args) { - if (argCount != 1) { - runtimeError(vm, "listdir() takes 1 argument (%d given)", argCount); + if (argCount > 1) { + runtimeError(vm, "listdir() takes 0 or 1 arguments (%d given)", argCount); return EMPTY_VAL; } - if (!IS_STRING(args[0])) { - runtimeError(vm, "listdir() argument must be a string"); - return EMPTY_VAL; + char *path; + if (argCount == 0) { + path = "."; + } else { + if (!IS_STRING(args[0])) { + runtimeError(vm, "listdir() argument must be a string"); + return EMPTY_VAL; + } + path = AS_CSTRING(args[0]); } ObjList *dir_contents = initList(vm); push(vm, OBJ_VAL(dir_contents)); - char *path = AS_CSTRING(args[0]); struct dirent *dir; DIR *d; d = opendir(path); From dd3ad1278eccd77dcfeec4e8c63804ebd16f2a40 Mon Sep 17 00:00:00 2001 From: The Great Cookie Machine <39784551+TheGreatCookieMachine@users.noreply.github.com> Date: Sun, 4 Oct 2020 15:16:10 -0700 Subject: [PATCH 41/61] Allow Path.isdir to work on Windows --- c/optionals/path.c | 4 ++++ docs/docs/path.md | 2 -- tests/path/isdir.du | 8 ++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/c/optionals/path.c b/c/optionals/path.c index a4b585b3..5163b762 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -1,5 +1,9 @@ #include "path.h" +#if defined(_WIN32) && !defined(S_ISDIR) +#define S_ISDIR(M) (((M) & _S_IFDIR) == _S_IFDIR) +#endif + #ifdef HAS_REALPATH static Value realpathNative(VM *vm, int argCount, Value *args) { if (argCount != 1) { diff --git a/docs/docs/path.md b/docs/docs/path.md index e4250f3b..bf54ce21 100644 --- a/docs/docs/path.md +++ b/docs/docs/path.md @@ -97,8 +97,6 @@ Path.exists("some/path/to/a/file.du"); // true Checks whether a given path points to a directory or not. -**Note:** This is not available on windows systems yet. - ```js Path.isdir("/usr/bin/"); //true ``` diff --git a/tests/path/isdir.du b/tests/path/isdir.du index 4c052a7a..98753746 100644 --- a/tests/path/isdir.du +++ b/tests/path/isdir.du @@ -7,6 +7,10 @@ */ import Path; -assert(Path.isdir("/usr/bin") == true); -assert(Path.isdir("/home/") == true); +if (System.platform != "windows") { + assert(Path.isdir("/usr/bin") == true); + assert(Path.isdir("/home/") == true); +} + +assert(Path.isdir("tests") == true); assert(Path.isdir("tests/runTests.du") == false); \ No newline at end of file From 849ef343805e9ad314c21cef0b42df6c80124d8a Mon Sep 17 00:00:00 2001 From: The Great Cookie Machine <39784551+TheGreatCookieMachine@users.noreply.github.com> Date: Sun, 4 Oct 2020 16:11:03 -0700 Subject: [PATCH 42/61] Replace elif without condition with else --- c/optionals/system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/optionals/system.c b/c/optionals/system.c index 88f66485..3a2cc342 100644 --- a/c/optionals/system.c +++ b/c/optionals/system.c @@ -293,7 +293,7 @@ void initArgv(VM *vm, Table *table, int argc, const char *argv[]) { void initPlatform(VM *vm, Table *table) { #ifdef _WIN32 defineNativeProperty(vm, table, "platform", OBJ_VAL(copyString(vm, "windows", 7))); -#elif +#else struct utsname u; if (-1 == uname(&u)) { defineNativeProperty(vm, table, "platform", OBJ_VAL(copyString(vm, From 397a609b3986bc2fca09a68324ac41f52731435a Mon Sep 17 00:00:00 2001 From: The Great Cookie Machine <39784551+TheGreatCookieMachine@users.noreply.github.com> Date: Mon, 5 Oct 2020 18:05:34 -0700 Subject: [PATCH 43/61] Remove usage of Variable Length Arrays --- c/common.h | 5 ----- c/datatypes/number.c | 7 ------- c/optionals/datetime.c | 29 ++++++++++------------------- 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/c/common.h b/c/common.h index d3ffe937..a8d65fee 100644 --- a/c/common.h +++ b/c/common.h @@ -25,11 +25,6 @@ #define UINT8_COUNT (UINT8_MAX + 1) -// MSVC does not support VLAs in C99 but also doesn't define __STDC_NO_VLA__. As such we must check _MSC_VER separately. -#if (defined(__STDC__) && !defined(__STDC_VERSION__)) || defined(__STDC_NO_VLA__) || defined(_MSC_VER) -#define NO_VLA -#endif - typedef struct _vm VM; #endif diff --git a/c/datatypes/number.c b/c/datatypes/number.c index 8e20b62d..c45ecc94 100644 --- a/c/datatypes/number.c +++ b/c/datatypes/number.c @@ -12,23 +12,16 @@ static Value toStringNumber(VM *vm, int argCount, Value *args) { double number = AS_NUMBER(args[0]); int numberStringLength = snprintf(NULL, 0, "%.15g", number) + 1; - #ifdef NO_VLA char *numberString = malloc(numberStringLength); if (numberString == NULL) { runtimeError(vm, "Memory error on toString()!"); return EMPTY_VAL; } - #else - char numberString[numberStringLength]; - #endif snprintf(numberString, numberStringLength, "%.15g", number); Value value = OBJ_VAL(copyString(vm, numberString, numberStringLength - 1)); - #ifdef NO_VLA free(numberString); - #endif - return value; } diff --git a/c/optionals/datetime.c b/c/optionals/datetime.c index 2f14a91b..fb0030cd 100644 --- a/c/optionals/datetime.c +++ b/c/optionals/datetime.c @@ -84,16 +84,12 @@ static Value strftimeNative(VM *vm, int argCount, Value *args) { struct tm tictoc; int len = (format->length > 128 ? format->length * 4 : 128); - #ifdef NO_VLA - char *buffer = malloc(len); - if (buffer == NULL) { - runtimeError(vm, "Memory error on toString()!"); + + char *point = malloc(len); + if (point == NULL) { + runtimeError(vm, "Memory error on strftime()!"); return EMPTY_VAL; } - #else - char buffer[len]; - #endif - char *point = buffer; gmtime_r(&t, &tictoc); @@ -120,22 +116,17 @@ static Value strftimeNative(VM *vm, int argCount, Value *args) { len *= 2; - if (buffer == point) - point = malloc (len); - else - point = realloc (point, len); - + point = realloc(point, len); + if (point == NULL) { + runtimeError(vm, "Memory error on strftime()!"); + return EMPTY_VAL; + } } res = copyString(vm, point, strlen(point)); theend: - if (buffer != point) - free(point); - - #ifdef NO_VLA - free(buffer); - #endif + free(point); return OBJ_VAL(res); } From e5b418ffb3d22f70f8767360a693598278842cb3 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Mon, 5 Oct 2020 20:28:12 -0700 Subject: [PATCH 44/61] Replace JavaScript and Python formatting with C# --- docs/docs/built-ins.md | 10 ++++----- docs/docs/classes.md | 40 ++++++++++++++++++------------------ docs/docs/control-flow.md | 22 ++++++++++---------- docs/docs/datetime.md | 10 ++++----- docs/docs/env.md | 8 ++++---- docs/docs/files.md | 10 ++++----- docs/docs/getting-started.md | 6 +++--- docs/docs/http.md | 10 ++++----- docs/docs/json.md | 8 ++++---- docs/docs/math.md | 20 +++++++++--------- docs/docs/modules.md | 8 ++++---- docs/docs/path.md | 18 ++++++++-------- docs/docs/sockets.md | 18 ++++++++-------- docs/docs/system.md | 36 ++++++++++++++++---------------- 14 files changed, 112 insertions(+), 112 deletions(-) diff --git a/docs/docs/built-ins.md b/docs/docs/built-ins.md index 14dff933..5c85fb10 100644 --- a/docs/docs/built-ins.md +++ b/docs/docs/built-ins.md @@ -29,7 +29,7 @@ Global functions which are built into Dictu. Prints a given list of values to stdout. -```js +```cs print(10); // 10 print("test"); // "test" print(10, "test", nil, true); // 10, "test", nil, true @@ -40,7 +40,7 @@ print(10, "test", nil, true); // 10, "test", nil, true Gathers user input from stdin and returns the value as a string. `input()` has an optional prompt which will be shown to the user before they enter their string. -```js +```cs input(); input("Input: "); ``` @@ -49,7 +49,7 @@ input("Input: "); Returns the type of a given value as a string. -```js +```cs type(10); // "number" type(true); // "bool" type([]); // "list" @@ -59,7 +59,7 @@ type([]); // "list" Raise a runtime error if the given boolean is not true. -```js +```cs assert(10 > 9); assert(9 > 10); // assert() was false! ``` @@ -68,7 +68,7 @@ assert(9 > 10); // assert() was false! Returns a boolean depending on whether a variable has been defined in the global scope. -```js +```cs isDefined("isDefined"); // true isDefined("garbage value"); // false ``` diff --git a/docs/docs/classes.md b/docs/docs/classes.md index c4417e72..55ca4170 100644 --- a/docs/docs/classes.md +++ b/docs/docs/classes.md @@ -21,7 +21,7 @@ Classes provide a means to gather functions and data together to provide a bluep ## Defining a class -```js +```cs class SomeClass { // Constructor init() { @@ -36,7 +36,7 @@ SomeClass(); // Object created! `init()` is the method name for a constructor in Dictu. A constructor is a method that is called when an object is instantiated. Instantiating an object, is just like invoking a function, except you "invoke" the class. You can also pass arguments to the constructor to be used. -```js +```cs class SomeClass { // Constructor init(message) { @@ -51,7 +51,7 @@ SomeClass("Object created!"); // Object created! Methods are functions defined within a class. When defining a method in Dictu, the `def` keyword is not used and instead its just the method name and parameter list. -```js +```cs class SomeClass { // Method printMessage() { @@ -67,7 +67,7 @@ SomeClass().printMessage(); // Hello! Classes and instances can both be converted to a string using the toString method. If you want a different string representation for an object you can overload the toString method in your class. -```js +```cs class Test {} class TestOverload { @@ -92,7 +92,7 @@ print(TestOverload().toString()); // 'Testing object' `this` is a variable which is passed to all methods which are not marked as static. `this` is a reference to the object you are currently accessing. `this` allows you to modify instance variables of a particular object. -```js +```cs class SomeClass { // Constructor init(message) { @@ -113,7 +113,7 @@ myObject.printMessage(); // Some text! Attributes in Dictu are instance attributes, and these attributes get defined either inside the methods or on the method directly. There is no concept of attribute access modifiers in python and attributes are available directly from the object without the need for getters or setters. -```js +```cs class Test { init() { this.x = 10; @@ -129,7 +129,7 @@ print(myObject.x); // 10 Attempting to access an attribute of an object that does not exist will throw a runtime error, and instead before accessing, you should check if the object has the given attribute. This is done via `hasAttribute`. -```js +```cs class Test { init() { this.x = 10; @@ -148,7 +148,7 @@ print(myObject.z); // Undefined property 'z'. Sometimes in Dictu we may wish to access an attribute of an object without knowing the attribute until runtime. We can do this via the `getAttribute` method. This method takes a string and an optional default value and returns either the attribute value or the default value (if there is no attribute and no default value, nil is returned). -```js +```cs class Test { init() { this.x = 10; @@ -166,7 +166,7 @@ print(myObject.getAttribute("y")); // nil Similar concept to `getAttribute` however this allows us to set an attribute on an instance. -```js +```cs class Test { init() { this.x = 10; @@ -183,7 +183,7 @@ print(myObject.x); // 100 A class variable, is a variable that is defined on the class and not the instance. This means that all instances of the class will have access to the class variable, and it is also shared across all instances. -```js +```cs class SomeClass { var classVariable = 10; // This will be shared among all "SomeClass" instances @@ -210,7 +210,7 @@ print(y.classVariable); // 100 Static methods are methods which do not reference an object, and instead belong to a class. If a method is marked as static, `this` is not passed to the object. This means static methods can be invoked without instantiating an object. -```js +```cs class SomeOtherClass { init(someArg) { this.someArg = someArg; @@ -230,14 +230,14 @@ SomeOtherClass.printHello(); SomeOtherClass.printMessage(); ``` Output -```js +```cs Hello [line 17] in script: 'printMessage' is not static. Only static methods can be invoked directly from a class. ``` ## Inheritance -```js +```cs class BaseClass { init() { this.someVariable = "Hello!"; @@ -267,7 +267,7 @@ An abstract class is a base class that can not be instantiated, like a trait, ho within a class. An abstract class can have methods which implement the body, and would work like a normal class being inherited, however, if it includes methods which have been marked as abstract, it enforces the inheriting class to implement these methods. -```js +```cs abstract class AbstractClass { // We do not define the body of an abstract method abstract test() @@ -296,7 +296,7 @@ Dictu only allows inheritance from a single parent class, which can cause compli This is where traits come into play. A trait is like a class, in the fact it has methods, and can deal with object attributes however, differ in the fact a trait can not be instantiated on its own. -```js +```cs trait MyTrait { hello() { print("Hello {}".format(this.name)); @@ -320,7 +320,7 @@ MyTrait(); // Runtime error: Can only call functions and classes. Sometimes we will have multiple traits, each with slightly different functionality, but we need functionality from all of these traits, in this instance, we can just use more than one trait. -```js +```cs trait MyTrait { hello() { print("Hello {}".format(this.name)); @@ -350,7 +350,7 @@ Traits also do not suffer from the diamond problem unlike multiple inheritance, are used and they have the same method, the last most used trait has precedence. This means the order of trait inclusion into a class is important. -```js +```cs trait MyTrait { hello() { print("Hello {}".format(this.name)); @@ -380,7 +380,7 @@ myObject.hello(); // Hello Jason Class instances are a mutable type, this means if you were to take the reference of an object and use it in a new variable and you mutate the instance in the new variable, it would mutate the object at the old variable, since its a reference to the same object. -```js +```cs class Test { init() { this.x = 10; @@ -400,7 +400,7 @@ To get around this, instances have two methods, obj.copy() and obj.deepCopy(). This method will take a shallow copy of the object, and create a new copy of the instance. Mutable types are still references and will mutate on both new and old if changed. See obj.deepCopy() to avoid this. -```js +```cs class Test { init() { this.x = 10; @@ -424,7 +424,7 @@ This method will take a deep copy of the object, and create a new copy of the in is if the object contains references to any mutable datatypes these will also be copied and returned as new values meaning, they will not be mutated on the old object. -```js +```cs class Test { init() { this.x = 10; diff --git a/docs/docs/control-flow.md b/docs/docs/control-flow.md index 62170017..d84c9675 100644 --- a/docs/docs/control-flow.md +++ b/docs/docs/control-flow.md @@ -1,6 +1,6 @@ --- layout: default -title: Control Flow +title: Control flow nav_order: 7 --- @@ -16,7 +16,7 @@ nav_order: 7 --- ## If statement -```js +```cs if (false or true) { var variable = "Hello"; print(variable); // Print is a native function so parenthesis are required @@ -44,7 +44,7 @@ if (x == 6) { ## Loops ### While loop -```js +```cs // While loop var i = 0; while (i < 10) { @@ -55,7 +55,7 @@ while (i < 10) { Dictu also implements syntactic sugar for a while true loop. -```js +```cs // While 'true' loop // If no expression is made, true is implicitly assumed while { @@ -66,7 +66,7 @@ while { ### For loop -```js +```cs // For loop for (var i = 0; i < 10; ++i) { print(i); @@ -77,7 +77,7 @@ for (var i = 0; i < 10; ++i) { Continue allows execution of a loop to restart prematurely. -```js +```cs // For loop for (var i = 0; i < 10; ++i) { if (i % 2 == 0) @@ -91,7 +91,7 @@ for (var i = 0; i < 10; ++i) { Break allows execution of a loop to stop prematurely. -```js +```cs // For loop for (var i = 0; i < 10; ++i) { if (i > 5) @@ -103,7 +103,7 @@ for (var i = 0; i < 10; ++i) { ## Functions -```python +```csthon //Define the function def someFunction() { print("Hello!"); @@ -129,7 +129,7 @@ print(someFunctionWithReturn()); // 10 Variables defined in a function are local to the scope of the function. -```python +```csthon def someFunction() { var myVariable = 10; print(myVariable); @@ -147,7 +147,7 @@ Output Functions can also be stored in variables, or within data structures such as lists. -```python +```csthon def someFunction() { print("Hello!"); } @@ -168,7 +168,7 @@ someList[0](someList[1]); // Hello! Functions can also have optional parameters. If a value is not passed, the parameter will take the default value given in the function header. Note: non-optional parameters **must** be defined before optional parameters. -```python +```csthon def someFunction(a, b=10) { print(a, b); } diff --git a/docs/docs/datetime.md b/docs/docs/datetime.md index c0b36ae0..44e62b85 100644 --- a/docs/docs/datetime.md +++ b/docs/docs/datetime.md @@ -19,7 +19,7 @@ nav_order: 13 To make use of the Datetime module an import is required. -```js +```cs import Datetime; ``` @@ -27,7 +27,7 @@ import Datetime; Returns a human readable locale datetime string. -```js +```cs Datetime.now(); // Fri May 29 03:12:32 2020 ``` @@ -35,7 +35,7 @@ Datetime.now(); // Fri May 29 03:12:32 2020 Returns a human readable UTC datetime string. -```js +```cs Datetime.now(); // Fri May 29 02:12:32 2020 ``` @@ -78,7 +78,7 @@ Returns a user-defined datetime formatted string, see [Datetime formats](#dateti which is a UNIX timestamp, so the date is formatted from the given timestamp rather than the current point in time. -```js +```cs Datetime.strftime("Today is %A"); // Today is Friday var time = System.time(); @@ -91,7 +91,7 @@ Returns a number which is the number of seconds from epoch. `strptime` expects t the first parameter being the date format, see [Datetime formats](#datetime-formats) and the second the date string in the format of the first parameter. -```js +```cs Datetime.strptime("%Y-%m-%d %H:%M:%S", "2020-01-01 00:00:00"); // 1577836800 ``` diff --git a/docs/docs/env.md b/docs/docs/env.md index ffcb860b..7523d464 100644 --- a/docs/docs/env.md +++ b/docs/docs/env.md @@ -19,7 +19,7 @@ nav_order: 16 To make use of the Env module an import is required. -```js +```cs import Env; ``` @@ -34,7 +34,7 @@ Get the string representation of an error. An optional error status can be passed, otherwise the default is Env.errno. It returns a string that describes the error. -```js +```cs print(Env.strerror()); ``` @@ -43,7 +43,7 @@ print(Env.strerror()); Get an environment variable. If the ENV var does not exist nil is returned and sets errno accordingly, otherwise a string value is returned. -```js +```cs Env.get("bad key!"); // nil Env.get("valid key"); // "value" ``` @@ -54,7 +54,7 @@ Change or add an environment variable. You can clear an ENV var by passing a `ni When setting an ENV var the key must be a string and the value must be either a string or nil. Returns 0 upon success or -1 otherwise and sets Env.errno accordingly. -```js +```cs Env.set("key", "test"); Env.set("key", nil); // Remove env var Env.set("key", 10); // set() arguments must be a string or nil. diff --git a/docs/docs/files.md b/docs/docs/files.md index ef871a03..ea3b73d2 100644 --- a/docs/docs/files.md +++ b/docs/docs/files.md @@ -31,7 +31,7 @@ when you leave the with scope automatically. | w+ | Opens a file for updating (read + write), if a file does not exist one is created, else existing file is overwritten | | a+ | Opens a file for updating (read + write), if a file does not exist one is created, else appends text to the end of a file. | -```js +```cs with("test.txt", "r") { // file var is passed in here } @@ -43,7 +43,7 @@ with("test.txt", "r") { There are two methods available when writing to a file: `write()` and `writeLine()`. `write()` simply writes strings to a file, `writeLine()` is exactly the same, except it appends a newline to the passed in string. Both functions return the amount of characters wrote to the file. -```js +```cs with("test.txt", "w") { // file var is passed in here file.writeLine("Hello!"); // 6 @@ -57,14 +57,14 @@ with("test.txt", "w") { There are two methods available when reading files: `read()` and `readLine()`. `read()` reads the entire file, and returns its content as a string. `readLine()` will read the file up to a new line character. -```js +```cs // Read entire file with("test.txt", "r") { print(file.read()); } ``` -```js +```cs // Read a file line by line with("test.txt", "r") { var line; @@ -87,7 +87,7 @@ The second argument (from) is for controlling where the cursor will be within th If the `from` parameter is not supplied, `seek()` will occur from the beginning of the file. -```js +```cs with("test.txt", "r") { print(file.read()); file.seek(0); // Go back to the start of the file diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md index 71428e7c..e185ced7 100644 --- a/docs/docs/getting-started.md +++ b/docs/docs/getting-started.md @@ -1,6 +1,6 @@ --- layout: default -title: Getting Started +title: Getting started nav_order: 2 --- @@ -20,7 +20,7 @@ We've already learned how to enter the REPL and run code there. Now, let's creat We're going to call our file `hello-world.du`: -```js +```cs print("Hello, World!"); ``` @@ -50,7 +50,7 @@ Dictu Version: {{ site.version }} It's always important to comment your code! Comments are used to explain what your code does. Dictu's syntax will be familiar to any programmer. -```js +```cs // This is a single line comment /* diff --git a/docs/docs/http.md b/docs/docs/http.md index d06d32fa..f81b0daa 100644 --- a/docs/docs/http.md +++ b/docs/docs/http.md @@ -19,7 +19,7 @@ nav_order: 18 To make use of the HTTP module an import is required. -```js +```cs import HTTP; ``` @@ -34,7 +34,7 @@ import HTTP; Sends a HTTP GET request to a given URL. Timeout is given in seconds. Returns a dictionary upon success or nil otherwise and sets HTTP.errno accordingly. -```js +```cs HTTP.get("https://httpbin.org/get"); HTTP.get("https://httpbin.org/get", 1); @@ -46,7 +46,7 @@ HTTP.get("https://httpbin.org/get", 1); Sends a HTTP POST request to a given URL.Timeout is given in seconds. Returns a dictionary upon success or nil otherwise and sets HTTP.errno accordingly. -```js +```cs HTTP.post("https://httpbin.org/post"); HTTP.post("https://httpbin.org/post", {"test": 10}); HTTP.post("https://httpbin.org/post", {"test": 10}, 1); @@ -61,7 +61,7 @@ the response Example response from [httpbin.org](https://httpbin.org) -```json +```cson // GET {"content": '{ @@ -105,6 +105,6 @@ Get the string representation of an error. An optional error status can be passed, otherwise the default is HTTP.errno. It returns a string that describes the error. -```js +```cs print(HTTP.strerror()); ``` diff --git a/docs/docs/json.md b/docs/docs/json.md index e1138eb9..ded55cfd 100644 --- a/docs/docs/json.md +++ b/docs/docs/json.md @@ -19,7 +19,7 @@ nav_order: 17 To make use of the JSON module an import is required. -```js +```cs import JSON; ``` @@ -27,7 +27,7 @@ import JSON; Parses a JSON string and turns it into a valid Dictu datatype. -```js +```cs JSON.parse('true'); // true JSON.parse('{"test": 10}'); // {"test": 10} JSON.parse('[1, 2, 3]'); // [1, 2, 3] @@ -38,7 +38,7 @@ JSON.parse('null'); // nil Stringify converts a Dictu value into a valid JSON string. -```js +```cs JSON.stringify(true); // 'true' JSON.stringify({"test": 10}); // '{"test": 10}' JSON.stringify([1, 2, 3]); // '[1, 2, 3]' @@ -47,7 +47,7 @@ JSON.stringify(nil); // 'null' Stringify also takes an optional `indent` parameter, which is a number of the amount of spaces to indent by, while also making the response multiline. -```js +```cs JSON.stringify([1, 2, 3], 4); // Output diff --git a/docs/docs/math.md b/docs/docs/math.md index dd2ba223..45f242ea 100644 --- a/docs/docs/math.md +++ b/docs/docs/math.md @@ -20,7 +20,7 @@ nav_order: 14 To make use of the Math module an import is required. For the purpose of the documentation, an iterable is either a list, or passing multiple arguments to the function directly. -```js +```cs import Math; ``` @@ -35,7 +35,7 @@ import Math; Return the smallest number within the iterable -```js +```cs Math.min(1, 2, 3); // 1 Math.min([1, 2, 3]); // 1 ``` @@ -44,7 +44,7 @@ Math.min([1, 2, 3]); // 1 Return the largest number within the iterable -```js +```cs Math.min(1, 2, 3); // 3 Math.min([1, 2, 3]); // 3 ``` @@ -53,7 +53,7 @@ Math.min([1, 2, 3]); // 3 Return the average of the iterable -```js +```cs Math.average(1, 2, 3); // 2 Math.average([1, 2, 3]); // 2 ``` @@ -62,7 +62,7 @@ Math.average([1, 2, 3]); // 2 Return the sum of the iterable -```js +```cs Math.sum(1, 2, 3); // 6 Math.sum([1, 2, 3]); // 6 ``` @@ -71,7 +71,7 @@ Math.sum([1, 2, 3]); // 6 Return the largest integer less than or equal to the given input -```js +```cs Math.floor(17.4); // 17 Math.floor(17.999); // 17 Math.floor(17); // 17 @@ -81,7 +81,7 @@ Math.floor(17); // 17 Round to the nearest integer -```js +```cs Math.round(17.4); // 17 Math.round(17.49); // 17 Math.round(17.5); // 18 @@ -91,7 +91,7 @@ Math.round(17.5); // 18 Returns smallest integer greater than or equal to given input -```js +```cs Math.ceil(17.4); // 18 Math.ceil(17.999); // 18 Math.ceil(17); // 17 @@ -101,7 +101,7 @@ Math.ceil(17); // 17 Returns absolute value of a given number -```js +```cs Math.abs(-10); // 10 Math.abs(10); // 10 Math.abs(-10.5); // 10.5 @@ -111,7 +111,7 @@ Math.abs(-10.5); // 10.5 Returns the square root of a given number -```js +```cs Math.sqrt(25); // 5 Math.sqrt(100); // 10 ``` diff --git a/docs/docs/modules.md b/docs/docs/modules.md index df71b209..acb130ca 100644 --- a/docs/docs/modules.md +++ b/docs/docs/modules.md @@ -27,7 +27,7 @@ a variable defined in `file.du` will not overwrite a variable in `file1.du` if i When you wish to import a module from the standard library you use the import keyword. Importing from the standard library is slightly different to importing a user created script (see below). -```js +```cs import Math; Math.PI; // 3.14... @@ -39,7 +39,7 @@ When you wish to import another Dictu script, you use the import keyword. This t identifier of the module being imported. This is different to importing from the standard library as a string path is passed rather than an identifier. -```js +```cs // Module not imported into current namespace, however the code in "some/file.du" is still ran. import "some/file.du"; @@ -51,7 +51,7 @@ When importing a module with an identifer, you can access the top level module v like you would for a class. **some/file.du** -```js +```cs var x = 10; def test() { @@ -60,7 +60,7 @@ def test() { ``` **main.du** -```js +```cs import "some/file.du" as SomeModule; print(SomeModule.x); // 10 diff --git a/docs/docs/path.md b/docs/docs/path.md index e4250f3b..b96199f9 100644 --- a/docs/docs/path.md +++ b/docs/docs/path.md @@ -19,7 +19,7 @@ nav_order: 15 To make use of the Path module an import is required. -```js +```cs import Path; ``` @@ -35,7 +35,7 @@ import Path; Returns the basename of string. -```js +```cs Path.basename("/usr/bin"); // 'bin' ``` @@ -43,7 +43,7 @@ Path.basename("/usr/bin"); // 'bin' Returns the directory name of string. -```js +```cs Path.dirname("/usr/bin"); // '/usr' ``` @@ -51,7 +51,7 @@ Path.dirname("/usr/bin"); // '/usr' Returns the extension portion of string, including the dot. -```js +```cs Path.extname("/tmp/t.ext"); // '.ext' Path.extname("/tmp/t"); // '' ``` @@ -60,7 +60,7 @@ Path.extname("/tmp/t"); // '' Returns true if string is an absolute path or false otherwise. -```js +```cs Path.isAbsolute("/usr"); // true Path.isAbsolute("usr"); // false ``` @@ -71,7 +71,7 @@ An optional error status can be passed, otherwise the default is Path.errno. It returns a string that describes the error. **Note:** This is not available on windows systems. -```js +```cs print(Path.strerror()); ``` @@ -81,7 +81,7 @@ Returns the canonicalized absolute pathname or nil on error and sets Path.errno **Note:** This is not available on windows systems. -```js +```cs Path.realpath("/dir/../dir/../dir"); // '/dir' ``` @@ -89,7 +89,7 @@ Path.realpath("/dir/../dir/../dir"); // '/dir' Returns a boolean whether a file exists at a given path. -```js +```cs Path.exists("some/path/to/a/file.du"); // true ``` @@ -99,7 +99,7 @@ Checks whether a given path points to a directory or not. **Note:** This is not available on windows systems yet. -```js +```cs Path.isdir("/usr/bin/"); //true ``` diff --git a/docs/docs/sockets.md b/docs/docs/sockets.md index 05a2513b..59df66bb 100644 --- a/docs/docs/sockets.md +++ b/docs/docs/sockets.md @@ -19,7 +19,7 @@ nav_order: 18 To make use of the Socket module an import is required. -```js +```cs import Socket; ``` @@ -38,7 +38,7 @@ import Socket; Create a new socket object given a socket type and socket family. This will return a new socket object in which the rest of the methods are ran on. -```js +```cs var socket = Socket.create(Socket.AF_INET, Sockket.SOCK_STREAM); ``` @@ -47,7 +47,7 @@ var socket = Socket.create(Socket.AF_INET, Sockket.SOCK_STREAM); This will bind a given socket object to an IP and port number. On failure `nil` is returned and `errno` is set accordingly. -```js +```cs if (!socket.bind("host", 10)) { print(Socket.strerror()); // ... @@ -61,7 +61,7 @@ pending connections can be queued before they begin to get rejected. If left uns a reasonable value is chosen. `listen()` will return `nil` on failure and set `errno` accordingly or `true` on success. -```js +```cs if (!socket.listen()) { print(Socket.strerror()); // ... @@ -73,7 +73,7 @@ if (!socket.listen()) { This will accept incoming connections. This will create a **new** socket object on which you should operate. -```js +```cs var client = socket.accept(); ``` @@ -82,7 +82,7 @@ var client = socket.accept(); This will write data to the remote client socket. On failure `nil` is returned and `errno` is set accordingly, otherwise the amount of characters sent is returned. -```js +```cs if (!socket.write("Some Data")) { print(Socket.strerror()); // ... @@ -97,7 +97,7 @@ otherwise a string is returned. Note: The argument passed to recv should be a relatively small power of 2, such as 2048 or 4096. -```js +```cs if (!socket.recv(2048)) { print(Socket.strerror()); // ... @@ -108,7 +108,7 @@ if (!socket.recv(2048)) { Closes a socket. -```js +```cs socket.close(); ``` @@ -117,7 +117,7 @@ socket.close(); Set a socket option on a given socket. On failure `nil` is returned and `errno` is set accordingly, otherwise a string is returned. -```js +```cs if (!socket.setsockopt(Socket.SOL_SOCKET, Socket.SO_REUSEADDR)) { print(Socket.strerror()); // ... diff --git a/docs/docs/system.md b/docs/docs/system.md index 5e02da29..e7d3df95 100644 --- a/docs/docs/system.md +++ b/docs/docs/system.md @@ -48,7 +48,7 @@ Get the string representation of an error. An optional error status can be passed, otherwise the default is System.errno. It returns a string that describes the error. -```js +```cs print(System.strerror()); ``` @@ -61,7 +61,7 @@ It can take an optional number argument that specifies the mode. If a mode is no The actual permissions is modified by the process umask, which typically is S_IWGRP\|S_IWOTH (octal 022). -```js +```cs var S_IRWXU = System.S_IRWXU, S_IRGRP = System.S_IRGRP, @@ -79,7 +79,7 @@ Returns 0 upon success or -1 otherwise and sets System.errno accordingly. **Note:** This method and the F_OK|X_OK|W_OK|R_OK constants are not available on windows systems. -```js +```cs var F_OK = System.F_OK; System.access("/", F_OK); @@ -91,7 +91,7 @@ Remove directory. Returns 0 upon success or -1 otherwise and sets System.errno accordingly. -```js +```cs System.rmdir(dir); ``` @@ -101,7 +101,7 @@ Delete a file from filesystem. Returns 0 upon success or -1 otherwise and sets System.errno accordingly. -```js +```cs System.remove(file); ``` @@ -109,7 +109,7 @@ System.remove(file); Returns the process ID (PID) of the calling process. -```js +```cs System.getpid(); ``` @@ -117,7 +117,7 @@ System.getpid(); Returns the process ID of the parent of the calling process -```js +```cs System.getppid(); ``` @@ -125,7 +125,7 @@ System.getppid(); Returns the real user ID of the calling process. -```js +```cs System.getuid(); ``` @@ -133,7 +133,7 @@ System.getuid(); Returns the effective user ID of the calling process. -```js +```cs System.geteuid(); ``` @@ -141,7 +141,7 @@ System.geteuid(); Returns the real group ID of the calling process. -```js +```cs System.getgid(); ``` @@ -149,7 +149,7 @@ System.getgid(); Returns the effective group ID of the calling process. -```js +```cs System.getegid(); ``` @@ -159,7 +159,7 @@ Get the current working directory of the Dictu process. Returns a string upon success or nil otherwise and sets System.errno accordingly. -```js +```cs System.getCWD(); // '/Some/Path/To/A/Directory' ``` @@ -169,7 +169,7 @@ Set current working directory of the Dictu process. Returns 0 upon success or -1 otherwise and sets System.errno accordingly. -```js +```cs if (System.setCWD('/') == -1) { print ("failed to change directory"); } @@ -179,7 +179,7 @@ if (System.setCWD('/') == -1) { Sleep pauses execution of the program for a given amount of time in seconds. -```js +```cs System.sleep(3); // Pauses execution for 3 seconds ``` @@ -187,7 +187,7 @@ System.sleep(3); // Pauses execution for 3 seconds Returns number of clock ticks since the start of the program, useful for benchmarks. -```js +```cs System.clock(); ``` @@ -195,7 +195,7 @@ System.clock(); Returns UNIX timestamp. -```js +```cs System.time(); ``` @@ -203,7 +203,7 @@ System.time(); Manually trigger a garbage collection. -```js +```cs System.collect(); ``` @@ -211,7 +211,7 @@ System.collect(); When you wish to prematurely exit the script with a given exit code. -```js +```cs System.exit(10); ``` From 2b1dbd658df40ec6b6d9d6fc347d0b2177b98218 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Mon, 5 Oct 2020 20:28:19 -0700 Subject: [PATCH 45/61] Begin rewriting --- docs/docs/collections.md | 104 +++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/docs/docs/collections.md b/docs/docs/collections.md index bf84036f..10ce670c 100644 --- a/docs/docs/collections.md +++ b/docs/docs/collections.md @@ -1,10 +1,10 @@ --- layout: default -title: Collections +title: Data structures nav_order: 5 --- -# Collections +# Data structures {: .no_toc } ## Table of contents @@ -16,25 +16,26 @@ nav_order: 5 --- ## Lists -Lists in Dictu are a type that allows you to store more than one value in a single data structure. Lists will automatically resize for you, and can hold any data type within them. +Lists in Dictu allow you to store mutliple values of any type. Lists automatically resize for you as data is added and removed. Lists are similar to arrays in languages like PHP, JavaScript, and Ruby. -```js -var myList = [1, 2, "hi", true, false, nil]; +```cs +var list = [1, 2.3, "Mango", false, nil]; ``` ### Indexing -```js -var myList = [1, 2, 3]; -// Lists are 0 indexed. -print(myList[0]); // 1 +Lists are 0-indexed, meaning that 0 is the first item in a list, and 1 is the second item. You can access an item at a specific index using square brackets. + +```cs +var list = [1, 2, 3]; +print(list[0]); // 1 ``` -Updating a value within a list uses the same syntax, except you supply a value via assignment. +You can use the same syntax to update a value in a list, except you must provide a value. -```js -var myList = [1, 5, 3]; -myList[1] = 2; // [1, 2, 3] +```cs +var list = [1, 5, 3]; +list[1] = 2; // [1, 2, 3] ``` ### Slicing @@ -42,20 +43,25 @@ myList[1] = 2; // [1, 2, 3] Slicing is technique used when we wish to return part of a list. It has a syntax of [start:end] where start and end are optional as long as one is provided. -E.g `[1, 2, 3, 4, 5][1:]` or `[1, 2, 3, 4, 5][:5]` are both valid. The start index is inclusive but the end index is exclusive. +If you want to return only part of a list, you slice it! To slice a list, use square brackets with the range you want to slice. The starting index is inclusive, but the ending index is exclusive. You can also use negative numbers to get characters from the end of a list. Only one index is required. -```py +```cs [1, 2, 3, 4, 5][1:]; // [2, 3, 4, 5] [1, 2, 3, 4, 5][:4]; // [1, 2, 3, 4] [1, 2, 3, 4, 5][1:4]; // [2, 3, 4] [1, 2, 3, 4, 5][2:4]; // [3, 4] +[1, 2, 3, 4, 5][0]; // 1 +[1, 2, 3, 4, 5][-1]; // 5 ``` + +[comment]: Start improving here! -Jerome + ### Adding to lists #### list.push(value) To add append a new value to a list, use the `.push()` method. -```js +```cs var myList = []; myList.push(10); // [10] myList.push(11); // [10, 11] @@ -65,7 +71,7 @@ myList.push(11); // [10, 11] To insert a value into a list at a given index without replacing the value use .insert(). -```js +```cs var x = [10, 12]; // Can insert to a list. This will not replace the value. @@ -77,7 +83,7 @@ myList.insert(11, 1); // [10, 11, 12] Using the + operator on lists will join two lists and return a new list. It must be used on two values which are both lists. -```js +```cs var x = [10]; x + [11, 12]; @@ -91,7 +97,7 @@ Similar to the + operator however this mutates the list the method is called on **Note:** values are not copied to the new list, they are just referenced. This means if the value is mutable it will mutate in the extended list as well. -```js +```cs var x = []; x.extend([1, 2, 3]); print(x); // [1, 2, 3] @@ -103,7 +109,7 @@ print(x); // [1, 2, 3, 1, 2, 3] Converts a list to a string. -```js +```cs ["1", 11].toString(); // ['1', 11] ["1", [11, "1"]].toString(); // ['1', [11, '1']] ``` @@ -111,7 +117,7 @@ Converts a list to a string. Returns the length of the given list. -```js +```cs [1, 2, 3].len(); // 3 ``` @@ -119,7 +125,7 @@ Returns the length of the given list. Converts a list to a boolean. A list is a "truthy" value when it has a length greater than 0. -```js +```cs [].toBool(); // false [1].toBool(); // true [[]].toBool(); // true @@ -129,7 +135,7 @@ Converts a list to a boolean. A list is a "truthy" value when it has a length gr To check if a value contains within a list we use `.contains()` -```js +```cs var myList = [1, 2, 3]; myList.contains(2); // true myList.contains(10); // false @@ -140,7 +146,7 @@ myList.contains(10); // false To convert a list of elements to a string use `.join()` to concatenate elements together by a given delimiter. If a delimiter is not supplied `", "` is the default. -```js +```cs var myList = [1, 2, 3]; print(myList.join()); // "1, 2, 3" print(myList.join("")); // "123" @@ -155,7 +161,7 @@ the list a runtime error occurs. Use together with [list.contains()](#listcontai Note: If a list contains multiple values which are the same, a call to `.remove()` will only remove the first occurrence, not all. -```js +```cs var myList = [1, 2, 3]; myList.remove(3); print(myList); // [1, 2] @@ -167,7 +173,7 @@ print(myList); // [2] To remove a value from a list, with an optional index, use `.pop()` -```js +```cs var myList = [1, 2, 3]; // If no index is given, pops from the end var someNumber = myList.pop(); // 3 @@ -180,14 +186,14 @@ print(myList); // [2] #### list.copy() When you are working with a mutable datatype taking a reference of a list when creating a new variable will modify the original list. -```js +```cs var list1 = [1, 2]; var list2 = list1; list2[0] = 10; print(list1); // [10, 2] ``` To get around this we can make copies of the list. Dictu offers the ability to both shallow and deep copy a list. -```js +```cs var list1 = [1, 2]; var list2 = list1.copy(); // shallow copy list2[0] = 10; @@ -197,7 +203,7 @@ print(list2); // [10, 2] #### list.deepCopy() To get around this, we can deepCopy the list. -```js +```cs var list1 = [[1, 2]]; var list2 = list1.deepCopy(); list2[0][0] = 10; @@ -211,7 +217,7 @@ print(list2); // [[10, 2]] To sort numeric lists (that is lists that contain only numbers) you can use the method sort. -```js +```cs var list1 = [1, -1, 4, 2, 10, 5, 3]; print(list1); // [1, -1, 4, 2, 10, 5, 3] @@ -224,7 +230,7 @@ print(list1); // [-1, 1, 2, 3, 4, 5, 10] Dictionaries are a key:value pair data type. Dictu requires that the dictionary key be an immutable type (nil, boolean, number, string), however the value can be any type. -```js +```cs var myDict = {"key": 1, "key1": true}; ``` @@ -233,7 +239,7 @@ var myDict = {"key": 1, "key1": true}; Accessing dictionary items is the same syntax as lists, except instead of an index, it expects an immutable type (nil, boolean, number, string) for it's key. If you try to access a key that does not exist, `nil` is returned. If you expect a key may not exist `.get()` can be used to return a default value. -```js +```cs var myDict = {"key": 1, "key1": true}; var someItem = myDict["key"]; // 1 var nilValue = myDict["unknown key"]; // nil @@ -241,14 +247,14 @@ var nilValue = myDict["unknown key"]; // nil Updating a value within a dictionary uses the same syntax, except you supply a value via assignment. -```js +```cs var myDict = {"key": 1, "key1": true}; var myDict["key"] = false; // {"key": false, "key1": true} ``` Adding a value to a dictionary is the same as updating a value, however if the key does not exist it is created. -```js +```cs var myDict = {"key": 1, "key1": true}; var myDict["key2"] = nil; // {"key": false, "key1": true, "key3": nil} ``` @@ -258,7 +264,7 @@ var myDict["key2"] = nil; // {"key": false, "key1": true, "key3": nil} Returns the dictionary value at the given key, or returns the default value if the key does not exist in the dictionary. If the key does not exist and no default is provided `nil` is returned. -```js +```cs var myDict = {}; myDict.get("unknown key", "No key!"); // No key! @@ -270,7 +276,7 @@ myDict.get("unknown key"); // nil Returns a list of all of the dictionary keys. -```js +```cs var myDict = {1: 2, "test": 3}; myDict.keys(); // [1, "test"] @@ -279,7 +285,7 @@ myDict.keys(); // [1, "test"] ### dict.toString() Converts a dictionary to a string. -```js +```cs {"1": 1, 1: "1"}.toString(); // '{"1": 1, 1: "1"}' {"1": {1: "1", "1": 1}, 1: "1"}.toString(); // '{"1": {"1": 1, 1: "1"}, 1: "1"}' ``` @@ -288,7 +294,7 @@ Converts a dictionary to a string. Converts a dictionary to a boolean. A dictionary is a "truthy" value when it has a length greater than 0. -```js +```cs var x = {}; x.toBool(); // false @@ -300,7 +306,7 @@ x.toBool(); // true Returns the length of the given dictionary. -```js +```cs {1: "one", 2: "two", 3: "three"}.len(); // 3 ``` @@ -308,7 +314,7 @@ Returns the length of the given dictionary. To check if a key exists within a dictionary use `.exists()` -```js +```cs var myDict = {"key": 1, "key1": true}; var keyExists = myDict.exists("key"); // true var keyDoesNotExist = myDict.exists("unknown key"); // false @@ -320,7 +326,7 @@ To remove a key from a dictionary use `.remove()`. **Note**: If you try to remove a key that does not exist a runtime error is raised, use together with `.exists()`. -```js +```cs var myDict = {"key": 1, "key1": true}; myDict.remove("key"); myDict; // {'key1': true} @@ -331,7 +337,7 @@ myDict.remove("unknown key"); // [line 1] in script: Key 'unknown key' passed to This is the exact same scenario as lists, so refer to [copying Lists](#copying-lists) for information as to what is happening. -```js +```cs var myDict = {"key": {"test": 10}}; var myDict1 = myDict.copy(); // Shallow copy var myDict2 = myDict.deepCopy(); // Deep copy @@ -341,7 +347,7 @@ var myDict2 = myDict.deepCopy(); // Deep copy Sets are an unordered collection of unique hashable values. Set values must be of type string, number, boolean or nil. -```js +```cs var mySet = set("test", 10); print(mySet); // {10, "test"} ``` @@ -349,7 +355,7 @@ print(mySet); // {10, "test"} ### set.toString() Converts a given set to a string. -```js +```cs var set_a = set(); set_a.add("one"); @@ -367,7 +373,7 @@ set_b.toString(); // '{2, 1}' Converts a set to a boolean. A set is a "truthy" value when it has a length greater than 0. -```js +```cs var x = set(); x.toBool(); // false @@ -379,7 +385,7 @@ x.toBool(); // true Returns the length of the given set. -```js +```cs var mySet = set(); mySet.add("Dictu!"); mySet.len(); // 1 @@ -389,7 +395,7 @@ mySet.len(); // 1 Adding to sets is just a case of passing a value to .add() -```js +```cs var mySet = set(); mySet.add("Dictu!"); ``` @@ -398,7 +404,7 @@ mySet.add("Dictu!"); To check if a set contains a value use `.contains()` -```js +```cs var mySet = set(); mySet.add("Dictu!"); print(mySet.contains("Dictu!")); // true @@ -411,7 +417,7 @@ To remove a value from a set use `.remove()`. **Note**: If you try to remove a value that does not exist a runtime error is raised, use together with `.contains()`. -```js +```cs var mySet = set(); mySet.add("Dictu!"); mySet.remove("Dictu!"); From 6a3378b205c9eb68324010558e16da05486c4598 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Mon, 5 Oct 2020 20:28:24 -0700 Subject: [PATCH 46/61] Complete rewrite --- docs/docs/strings.md | 173 ++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 78 deletions(-) diff --git a/docs/docs/strings.md b/docs/docs/strings.md index 39c481c1..812ed188 100644 --- a/docs/docs/strings.md +++ b/docs/docs/strings.md @@ -14,28 +14,28 @@ nav_order: 4 {:toc} --- -## Strings -Strings in Dictu are an immutable data type, this means, once a string has been created there is no way to modify a string directly, and instead a new string is created. Strings are created by having some sort of text between quotes, `"hello"` or `'hello'` is fine in Dictu. + +Strings in Dictu are an immutable data type. This means taht once a string has been created, there is no way to modify a string directly. Instead, a new string is created. Strings are indicated with quotation marks. In Dictu, you can use `'single'` or `"double"` quotes. They are treated the same. ### Concatenation -To join strings together use the `+` operator. +Use a plus sign to join string together. This is called concatenation. -```py -"hello " + "there!"; // "hello there!" +```cs +"This item costs " + "27" + " euros"; // "This item costs 27 euros" ``` ### Indexing -Strings can be indexed just like you can with lists, to return single characters, or to loop over strings. +You can access a specific letter in a string with the same syntax you would use to access an item in a list. -```py -var x = "Dictu"; +```cs +var string = "Dictu"; -x[0]; // D +string[0]; // D for (var i = 0; i < x.len(); ++i) { - print(x[i]); + print(string[i]); } // D // i @@ -49,177 +49,194 @@ for (var i = 0; i < x.len(); ++i) { Slicing is technique used when we wish to return a substring. It has a syntax of [start:end] where start and end are optional as long as one is provided. -E.g `"Dictu"[1:]` or `"Dictu"[:5]` are both valid. The start index is inclusive but the end index is exclusive. +If you want to get only part of a string, you slice it! To slice a string, use square brackets with the range you want to slice. The starting index is inclusive, but the ending index is exclusive. You can also use negative numbers to get characters from the end of a string. -```py +```cs "Dictu"[1:]; // ictu "Dictu"[:4]; // Dict "Dictu"[1:4]; // ict "Dictu"[2:4]; // ct +"Dictu"[-1]; // u + +"Dictu"[100]; // String index out of bounds. +"Dictu"[100:101]; // '' (empty string) +"Dictu"[0:100]; // Dictu ``` ### Escape codes -|--------------|---------------------------------------------| -| Escape code | Description | -| \n | \n is the escape code for a new line | -| \r | \r is the escape code for a carriage return | -| \t | \t is the escape code for a horizontal tab | -| \v | \v is the escape code for a vertical tab | -| \\\ | \\\ is the escape code for a backslash | -| \\" | \\" is the escape code for double quotes | -| \\' | \\' is the escape code for single quotes | +“Escape codes” are used to create things like new lines and tabs. Because backslashes are used in escape codes, you need to type two backshashes (`\\`) to use a single backslash. + +| \n | \n is the escape code for a new line | +| \r | \r is the escape code for a carriage return | +| \t | \t is the escape code for a horizontal tab | +| \v | \v is the escape code for a vertical tab | +| \\\ | \\\ is the escape code for a backslash | +| \\" | \\" is the escape code for double quotes | +| \\' | \\' is the escape code for single quotes | + +You should only need the escape codes for single and double quotes if you are using that type of quote within a string indicated with the same type. If that doesn't make sense, you'll quickly realize it won't work when you come across it. #### Raw strings -Sometimes when you are creating a string, you want the escape codes to be ignored, and -instead work with the literal values. Prefixing a string with r will create a "raw string". +Sometimes, you wil need to ignore escape codes. Simply prefix your string with an `r` and any escape codes will be ignored. -```py -r"test\ntest"; // "test\ntest" -r"test\ntest".len(); // 10 +```cs +// Normal Strings +"Dictu\trocks!"; // 'Dictu rocks!' +// Raw Strins +r"Dictu\trocks!"; // 'Dictu\trocks!' +r"Dictu\trocks!".len(); // 12 ``` ### string.len() Returns the length of the given string. -```py +```cs "string".len(); // 6 ``` ### string.lower() -To make all characters within a string lowercase, use the `.lower()` method. +Returns a lowercase version of the given string. -```py +```cs "DICTU".lower(); // dictu "DiCtU".lower(); // dictu +"dictu".lower(); // dictu ``` ### string.upper() -To make all characters within a string uppercase, use the `.upper()` method. +Returns an uppercase version of the given string. -```py +```cs "dictu".upper(); // DICTU "DiCtU".upper(); // DICTU +"DICTU".upper(); // DICTU ``` ### string.toNumber() -Converts a string to number. If it fails to parse nil is returned. +Casts a string to a number. Returns `nil` on failure. -```py +```cs "10.2".toNumber(); // 10.2 "10".toNumber(); // 10 +"10px".toNumber(); // nil ``` ### string.toBool() -Converts a string to a boolean. Strings are "truthy" when they have a length greater than 1. +Casts a string to a boolean value. Any string except an empty string is considered `true`. -```py +```cs "".toBool(); // false "false".toBool(); // true ``` ### string.startsWith(string) -To check if a string starts with a certain substring, use the `.startsWith()` method. +Returns true if a string starts with a given string. -```py -"dictu".startsWith("d"); // true -"dictu".startsWith("u"); // false +```cs +"Dictu".startsWith("D"); // true +"Dictu".startsWith("Dict"); // true +"Dictu".startsWith("Dictu"); // true +"Dictu".startsWith("q"); // false +"Dictu".startsWith("d"); // false ``` ### string.endsWith(string) -To check if a string ends with a certain substring, use the `.endsWith()` method. +Returns true if a string ends with a given string. -```py -"dictu".endsWith("d"); // false -"dictu".startsWith("u"); // true +```cs +"Dictu".endsWith("u"); // true +"Dictu".endsWith("tu"); // true +"Dictu".endsWith("Dictu"); // true +"Dictu".endsWith("ut"); // false +"Dictu".endsWith("q"); // false +"Dictu".endsWith("U"); // false ``` ### string.split(delimiter) -To split a string up into a list by a certain character or string, use the `.split()` method. +Returns a list of strings, split based on a given delimiter. -```py -"Dictu is great".split(" "); // ['Dictu', 'is', 'great'] +```cs +"Dictu is awesome!".split(" "); // ['Dictu', 'is', 'awesome!'] ``` ### string.replace(string: old, string: new) -To replace a substring within a string, use the `.replace()` method. +Replaces part (a substring) of a string with another string. -```py -"Dictu is okay".replace("okay", "great"); // "Dictu is great" +```cs +"Dictu is okay...".replace("okay...", "awesome!"); // "Dictu is awesome!" ``` ### string.contains(string) -To check if a string contains another string, use the `.contains()` method. +Returns true if a string contains another string. -```py -"Dictu is great".contains("Dictu"); // true +```cs +"Dictu is awesome!".contains("Dictu"); // true +"Dictu is awesome!".contains("Dictu is awesome!"); // true ``` ### string.find(string, number: skip -> optional) -To find the index of a given string, use the `.find()` method. - -Skip is an optional parameter which can be passed to skip the first `n` amount of appearances of the given substring. +To find the index of a given substring, use the `.find()` method. This method takes an optional second parameter which can be used to skip the first `n` number of appearances of the substring. This method returns `-1` if the substring could not be found. Otherwise, it returns the index of the string. -Returns -1 if the substring could not be found, otherwise it returns the index of the substring. - -```py +```cs "Hello, how are you?".find("how"); // 7 -"hello something hello".find("hello", 2); // 16 -- Skipped the first occurance of the word "hello" +"hello something hello".find("hello", 2); // 16 (Skipped first occurance) +"House".find("Lost Keys"); // -1 (Not found) ``` ### string.leftStrip() -To strip all whitespace at the beginning of a string, use the `.leftStrip()` method. +Strips whitespace from the left side of a string and returns the result. -```py -" hello".leftStrip(); // "hello" +```cs +" Dictu".leftStrip(); // "Dictu" ``` ### string.rightStrip() -To strip all whitespace at the end of a string, use the `.rightStrip()` method. +Strips whitespace from the right side of a string and returns the result. -```py -"hello ".rightStrip(); // "hello" +```cs +"Dictu ".rightStrip(); // "Dictu" ``` ### string.strip() -To strip whitespace at the beginning and end of a string, use the `.strip()` method. +Strips whitespace from both sides of a string and returns the result. -```py -" hello ".strip(); // "hello" +```cs +" Dictu ".strip(); // "Dictu" ``` ### string.format(...value: args...) -To format a string with any type of value `.format()` can be used. This will convert any type -to a string and swap placeholders `{}` for values. - -```py -"Hello {}".format("Jason"); // "Hello Jason" +This method will replace any instances of `{}` with the provided parameters. It also casts all arguments to strings. -"{} {} {} {}".format(10, "hi", [10, 20], {"test": 10}) // '10 hi [10, 20] {"test": 10}' +```cs +"Hello {}".format("Jerome"); // "Hello Jerome" +"Hello".format("Jerome"); // Error: format() placeholders do not match arguments +"Hello {}".format(); // Error: format() placeholders do not match arguments +"String: {}, Number: {}, Boolean: {}, List: {}, Dictionary: {}".format("String", 123, true, ["String", 123, true], {"key": "value"}); // "String: String, Number: 123, Boolean: true, List: ["String", 123, true], Dictionary: {"key": "value"}" ``` ### string.count(string) -To count the amount of occurrences of a given substring within another string. +Returns the number of occurrences of a given substring within another string. -```py +```cs "Dictu is great!".count("Dictu"); // 1 - +"This documentation".count("Good jokes"); // 0 "Sooooooooooome characters".count("o"); // 11 -``` +``` \ No newline at end of file From 3983753202181fcba944c4ac1d723325eff3c6d0 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Mon, 5 Oct 2020 20:28:44 -0700 Subject: [PATCH 47/61] Add set description --- docs/docs/variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/variables.md b/docs/docs/variables.md index e0a75ad6..48c6a475 100644 --- a/docs/docs/variables.md +++ b/docs/docs/variables.md @@ -23,7 +23,7 @@ nav_order: 3 | Boolean | true, false | | | List | [1, 2, ‘hi’, true, nil] | Lists can contain any data type or combination of data types. | | Dictionary | {“key1”: 10, 2: “two”, true: “true”, nil: “nil”} | Dictionaries have key-value pairs, like a dictionary (Word: Definition). Values can be any of the data types above except lists. | -| Set | | Sets are unordered collections of unique hashable values. | +| Set | `set("1", 1, "1")` will actually mean `{"1", 1}` | Sets are collections of unique values. You can create a set with the `set()` function, which returns a set. | | Nil | nil | Don’t confuse `nil` with `null`! While they mean the same thing in the English language, and the latter is more common in programming, `null` has no significance in Dictu. | ## Declaring a variable From fa73a62aecca3e05905e66102821bb17d1a81a77 Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Mon, 5 Oct 2020 20:28:57 -0700 Subject: [PATCH 48/61] Add fun fact about booleans :smile: --- docs/docs/variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/variables.md b/docs/docs/variables.md index 48c6a475..89c84e9b 100644 --- a/docs/docs/variables.md +++ b/docs/docs/variables.md @@ -20,7 +20,7 @@ nav_order: 3 | --- | --- | --- | | String | ‘foo’, “bar” | You can use single or double quotes to represent strings in Dictu. | | Number | 100, 100.5 | This data type includes both integers (whole numbers) and floats (numbers with decimals). | -| Boolean | true, false | | +| Boolean | true, false | Fun fact: Boolean data types are named after Robert Boole. | | List | [1, 2, ‘hi’, true, nil] | Lists can contain any data type or combination of data types. | | Dictionary | {“key1”: 10, 2: “two”, true: “true”, nil: “nil”} | Dictionaries have key-value pairs, like a dictionary (Word: Definition). Values can be any of the data types above except lists. | | Set | `set("1", 1, "1")` will actually mean `{"1", 1}` | Sets are collections of unique values. You can create a set with the `set()` function, which returns a set. | From 0ca930b8fdee1c86b929da5b09769e29e24114da Mon Sep 17 00:00:00 2001 From: Jerome Paulos Date: Tue, 6 Oct 2020 09:12:37 -0700 Subject: [PATCH 49/61] Suggested changes --- docs/docs/collections.md | 13 ++++--------- docs/docs/control-flow.md | 8 ++++---- docs/docs/http.md | 2 +- docs/docs/strings.md | 9 ++++----- docs/docs/variables.md | 2 +- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/docs/docs/collections.md b/docs/docs/collections.md index 10ce670c..d0766d70 100644 --- a/docs/docs/collections.md +++ b/docs/docs/collections.md @@ -1,10 +1,10 @@ --- layout: default -title: Data structures +title: Collections nav_order: 5 --- -# Data structures +# Collectionss {: .no_toc } ## Table of contents @@ -16,7 +16,7 @@ nav_order: 5 --- ## Lists -Lists in Dictu allow you to store mutliple values of any type. Lists automatically resize for you as data is added and removed. Lists are similar to arrays in languages like PHP, JavaScript, and Ruby. +Lists in Dictu allow you to store mutliple values of any type. Lists automatically resize for you as data is added and removed. Lists are similar to arrays in languages like Python, JavaScript, and Ruby. ```cs var list = [1, 2.3, "Mango", false, nil]; @@ -40,9 +40,6 @@ list[1] = 2; // [1, 2, 3] ### Slicing -Slicing is technique used when we wish to return part of a list. It has a syntax of [start:end] where start and end are optional -as long as one is provided. - If you want to return only part of a list, you slice it! To slice a list, use square brackets with the range you want to slice. The starting index is inclusive, but the ending index is exclusive. You can also use negative numbers to get characters from the end of a list. Only one index is required. ```cs @@ -50,11 +47,9 @@ If you want to return only part of a list, you slice it! To slice a list, use sq [1, 2, 3, 4, 5][:4]; // [1, 2, 3, 4] [1, 2, 3, 4, 5][1:4]; // [2, 3, 4] [1, 2, 3, 4, 5][2:4]; // [3, 4] -[1, 2, 3, 4, 5][0]; // 1 -[1, 2, 3, 4, 5][-1]; // 5 ``` -[comment]: Start improving here! -Jerome +[comment]: I'll continue here. -Jerome ### Adding to lists #### list.push(value) diff --git a/docs/docs/control-flow.md b/docs/docs/control-flow.md index d84c9675..7906c240 100644 --- a/docs/docs/control-flow.md +++ b/docs/docs/control-flow.md @@ -103,7 +103,7 @@ for (var i = 0; i < 10; ++i) { ## Functions -```csthon +```cs //Define the function def someFunction() { print("Hello!"); @@ -129,7 +129,7 @@ print(someFunctionWithReturn()); // 10 Variables defined in a function are local to the scope of the function. -```csthon +```cs def someFunction() { var myVariable = 10; print(myVariable); @@ -147,7 +147,7 @@ Output Functions can also be stored in variables, or within data structures such as lists. -```csthon +```cs def someFunction() { print("Hello!"); } @@ -168,7 +168,7 @@ someList[0](someList[1]); // Hello! Functions can also have optional parameters. If a value is not passed, the parameter will take the default value given in the function header. Note: non-optional parameters **must** be defined before optional parameters. -```csthon +```cs def someFunction(a, b=10) { print(a, b); } diff --git a/docs/docs/http.md b/docs/docs/http.md index f81b0daa..72aa9c92 100644 --- a/docs/docs/http.md +++ b/docs/docs/http.md @@ -61,7 +61,7 @@ the response Example response from [httpbin.org](https://httpbin.org) -```cson +```json // GET {"content": '{ diff --git a/docs/docs/strings.md b/docs/docs/strings.md index 812ed188..82f44fd6 100644 --- a/docs/docs/strings.md +++ b/docs/docs/strings.md @@ -15,7 +15,7 @@ nav_order: 4 --- -Strings in Dictu are an immutable data type. This means taht once a string has been created, there is no way to modify a string directly. Instead, a new string is created. Strings are indicated with quotation marks. In Dictu, you can use `'single'` or `"double"` quotes. They are treated the same. +Strings in Dictu are an immutable data type. This means that once a string has been created, there is no way to modify a string directly. Instead, a new string is created. Strings are indicated with quotation marks. In Dictu, you can use `'single'` or `"double"` quotes. They are treated the same. ### Concatenation @@ -33,6 +33,8 @@ You can access a specific letter in a string with the same syntax you would use var string = "Dictu"; string[0]; // D +string[-1]; // u +string[100]; // String index out of bounds. for (var i = 0; i < x.len(); ++i) { print(string[i]); @@ -56,9 +58,6 @@ If you want to get only part of a string, you slice it! To slice a string, use s "Dictu"[:4]; // Dict "Dictu"[1:4]; // ict "Dictu"[2:4]; // ct -"Dictu"[-1]; // u - -"Dictu"[100]; // String index out of bounds. "Dictu"[100:101]; // '' (empty string) "Dictu"[0:100]; // Dictu ``` @@ -192,7 +191,7 @@ To find the index of a given substring, use the `.find()` method. This method ta ```cs "Hello, how are you?".find("how"); // 7 -"hello something hello".find("hello", 2); // 16 (Skipped first occurance) +"hello something hello".find("hello", 2); // 16 (Skipped first occurence) "House".find("Lost Keys"); // -1 (Not found) ``` diff --git a/docs/docs/variables.md b/docs/docs/variables.md index 89c84e9b..fc05a2f2 100644 --- a/docs/docs/variables.md +++ b/docs/docs/variables.md @@ -23,7 +23,7 @@ nav_order: 3 | Boolean | true, false | Fun fact: Boolean data types are named after Robert Boole. | | List | [1, 2, ‘hi’, true, nil] | Lists can contain any data type or combination of data types. | | Dictionary | {“key1”: 10, 2: “two”, true: “true”, nil: “nil”} | Dictionaries have key-value pairs, like a dictionary (Word: Definition). Values can be any of the data types above except lists. | -| Set | `set("1", 1, "1")` will actually mean `{"1", 1}` | Sets are collections of unique values. You can create a set with the `set()` function, which returns a set. | +| Set | `set("1", 1, "1")` will actually mean `{"1", 1}` | Sets are unordered collections of hashable, unique values. You can create a set with the `set()` function, which returns a set. | | Nil | nil | Don’t confuse `nil` with `null`! While they mean the same thing in the English language, and the latter is more common in programming, `null` has no significance in Dictu. | ## Declaring a variable From e1b1d53955799928d996e1054dfecc9db4124b39 Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Tue, 6 Oct 2020 21:31:35 +0100 Subject: [PATCH 50/61] Update documentation --- docs/docs/collections.md | 4 +--- docs/docs/strings.md | 4 +++- docs/docs/variables.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/collections.md b/docs/docs/collections.md index d0766d70..e99c95a7 100644 --- a/docs/docs/collections.md +++ b/docs/docs/collections.md @@ -4,7 +4,7 @@ title: Collections nav_order: 5 --- -# Collectionss +# Collections {: .no_toc } ## Table of contents @@ -49,8 +49,6 @@ If you want to return only part of a list, you slice it! To slice a list, use sq [1, 2, 3, 4, 5][2:4]; // [3, 4] ``` -[comment]: I'll continue here. -Jerome - ### Adding to lists #### list.push(value) diff --git a/docs/docs/strings.md b/docs/docs/strings.md index 82f44fd6..179879b9 100644 --- a/docs/docs/strings.md +++ b/docs/docs/strings.md @@ -15,6 +15,8 @@ nav_order: 4 --- +## Strings + Strings in Dictu are an immutable data type. This means that once a string has been created, there is no way to modify a string directly. Instead, a new string is created. Strings are indicated with quotation marks. In Dictu, you can use `'single'` or `"double"` quotes. They are treated the same. ### Concatenation @@ -191,7 +193,7 @@ To find the index of a given substring, use the `.find()` method. This method ta ```cs "Hello, how are you?".find("how"); // 7 -"hello something hello".find("hello", 2); // 16 (Skipped first occurence) +"hello something hello".find("hello", 2); // 16 (Skipped first occurrence) "House".find("Lost Keys"); // -1 (Not found) ``` diff --git a/docs/docs/variables.md b/docs/docs/variables.md index 6de9ca20..88ab89da 100644 --- a/docs/docs/variables.md +++ b/docs/docs/variables.md @@ -23,7 +23,7 @@ nav_order: 3 | Boolean | true, false | Fun fact: Boolean data types are named after Robert Boole. | | List | [1, 2, ‘hi’, true, nil] | Lists can contain any data type or combination of data types. | | Dictionary | {“key1”: 10, 2: “two”, true: “true”, nil: “nil”} | Dictionaries have key-value pairs, like a dictionary (Word: Definition). Values can be any of the data types above except lists. | -| Set | `set("1", 1, "1")` will actually mean `{"1", 1}` | Sets are unordered collections of hashable, unique values. You can create a set with the `set()` function, which returns a set. | +| Set | `set("1", 1, "1")` will actually mean `{"1", 1}` | Sets are unordered collections of hashable, unique values. You can create a set with the `set()` function. | | Nil | nil | Don’t confuse `nil` with `null`! While they mean the same thing in the English language, and the latter is more common in programming, `null` has no significance in Dictu. | ## Declaring a variable From 1f625d9cd2268117a1cc6af2516ce7bc2656134d Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Wed, 7 Oct 2020 22:14:44 +0100 Subject: [PATCH 51/61] Make sure listdir is not compiled on windows machines with the current implementation --- c/optionals/path.c | 132 ++++++++++++++++++++++-------------------- c/optionals/path.h | 3 +- docs/docs/path.md | 2 + tests/path/listdir.du | 14 +++-- 4 files changed, 80 insertions(+), 71 deletions(-) diff --git a/c/optionals/path.c b/c/optionals/path.c index 864d0a27..6790e7d4 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -40,70 +40,6 @@ static Value isAbsoluteNative(VM *vm, int argCount, Value *args) { return (IS_DIR_SEPARATOR(path[0]) ? TRUE_VAL : FALSE_VAL); } -static Value isdirNative(VM *vm, int argCount, Value *args) { - if (argCount != 1) { - runtimeError(vm, "isdir() takes 1 argument (%d given)", argCount); - return EMPTY_VAL; - } - - if (!IS_STRING(args[0])) { - runtimeError(vm, "isdir() argument must be a string"); - return EMPTY_VAL; - } - - char *path = AS_CSTRING(args[0]); - struct stat path_stat; - stat(path, &path_stat); - - if (S_ISDIR(path_stat.st_mode)) - return TRUE_VAL; - - return FALSE_VAL; - -} - -static Value listdirNative(VM *vm, int argCount, Value *args) { - if (argCount > 1) { - runtimeError(vm, "listdir() takes 0 or 1 arguments (%d given)", argCount); - return EMPTY_VAL; - } - - char *path; - if (argCount == 0) { - path = "."; - } else { - if (!IS_STRING(args[0])) { - runtimeError(vm, "listdir() argument must be a string"); - return EMPTY_VAL; - } - path = AS_CSTRING(args[0]); - } - - ObjList *dir_contents = initList(vm); - push(vm, OBJ_VAL(dir_contents)); - struct dirent *dir; - DIR *d; - d = opendir(path); - if (d) { - while ((dir = readdir(d)) != NULL) { - char *inode_name = dir->d_name; - if (strcmp(inode_name, ".") == 0 || strcmp(inode_name, "..") == 0) - continue; - Value inode_value = OBJ_VAL(copyString(vm, inode_name, strlen(inode_name))); - push(vm, inode_value); - writeValueArray(vm, &dir_contents->values, inode_value); - pop(vm); - } - } else { - runtimeError(vm, "%s is not a path!", path); - return EMPTY_VAL; - } - - pop(vm); - - return OBJ_VAL(dir_contents); -} - static Value basenameNative(VM *vm, int argCount, Value *args) { if (argCount != 1) { runtimeError(vm, "basename() takes 1 argument (%d given)", argCount); @@ -232,6 +168,72 @@ static Value existsNative(VM *vm, int argCount, Value *args) { return BOOL_VAL(stat(path, &buffer) == 0); } +static Value isdirNative(VM *vm, int argCount, Value *args) { + if (argCount != 1) { + runtimeError(vm, "isdir() takes 1 argument (%d given)", argCount); + return EMPTY_VAL; + } + + if (!IS_STRING(args[0])) { + runtimeError(vm, "isdir() argument must be a string"); + return EMPTY_VAL; + } + + char *path = AS_CSTRING(args[0]); + struct stat path_stat; + stat(path, &path_stat); + + if (S_ISDIR(path_stat.st_mode)) + return TRUE_VAL; + + return FALSE_VAL; + +} + +#ifndef _WIN32 +static Value listdirNative(VM *vm, int argCount, Value *args) { + if (argCount > 1) { + runtimeError(vm, "listdir() takes 0 or 1 arguments (%d given)", argCount); + return EMPTY_VAL; + } + + char *path; + if (argCount == 0) { + path = "."; + } else { + if (!IS_STRING(args[0])) { + runtimeError(vm, "listdir() argument must be a string"); + return EMPTY_VAL; + } + path = AS_CSTRING(args[0]); + } + + ObjList *dir_contents = initList(vm); + push(vm, OBJ_VAL(dir_contents)); + struct dirent *dir; + DIR *d; + d = opendir(path); + if (d) { + while ((dir = readdir(d)) != NULL) { + char *inode_name = dir->d_name; + if (strcmp(inode_name, ".") == 0 || strcmp(inode_name, "..") == 0) + continue; + Value inode_value = OBJ_VAL(copyString(vm, inode_name, strlen(inode_name))); + push(vm, inode_value); + writeValueArray(vm, &dir_contents->values, inode_value); + pop(vm); + } + } else { + runtimeError(vm, "%s is not a path!", path); + return EMPTY_VAL; + } + + pop(vm); + + return OBJ_VAL(dir_contents); +} +#endif + ObjModule *createPathClass(VM *vm) { ObjString *name = copyString(vm, "Path", 4); push(vm, OBJ_VAL(name)); @@ -252,7 +254,9 @@ ObjModule *createPathClass(VM *vm) { defineNative(vm, &module->values, "dirname", dirnameNative); defineNative(vm, &module->values, "exists", existsNative); defineNative(vm, &module->values, "isdir", isdirNative); +#ifndef _WIN32 defineNative(vm, &module->values, "listdir", listdirNative); +#endif defineNativeProperty(vm, &module->values, "delimiter", OBJ_VAL( copyString(vm, PATH_DELIMITER_AS_STRING, PATH_DELIMITER_STRLEN))); diff --git a/c/optionals/path.h b/c/optionals/path.h index c706e3cd..93abbd89 100644 --- a/c/optionals/path.h +++ b/c/optionals/path.h @@ -3,7 +3,6 @@ #include #include -#include #include #ifndef PATH_MAX @@ -19,6 +18,8 @@ #define PATH_DELIMITER_AS_STRING ";" #define PATH_DELIMITER_STRLEN 1 #else +#include + #define HAS_REALPATH #define DIR_SEPARATOR '/' #define DIR_SEPARATOR_AS_STRING "/" diff --git a/docs/docs/path.md b/docs/docs/path.md index 2a2add7d..e555ec67 100644 --- a/docs/docs/path.md +++ b/docs/docs/path.md @@ -109,6 +109,8 @@ Returns a list of strings containing the contents of the input path. **Note:** This function does not guarantee any ordering of the returned list. +**Note:** This is not available on windows systems. + ```js Path.listdir("/"); // ["bin", "dev", "home", "lib", ...] ``` diff --git a/tests/path/listdir.du b/tests/path/listdir.du index d744caee..e1950aa7 100644 --- a/tests/path/listdir.du +++ b/tests/path/listdir.du @@ -6,11 +6,13 @@ */ import Path; -var dir_contents = Path.listdir("tests/path/test_dir"); -var exp_dir_contents = ["test_file_1", "test_file_2", "test_file_3"]; +if (System.platform != 'windows') { + var dir_contents = Path.listdir("tests/path/test_dir"); + var exp_dir_contents = ["test_file_1", "test_file_2", "test_file_3"]; -for (var i = 0; i < exp_dir_contents.len(); ++i) { - var exp_inode = exp_dir_contents[i]; - assert(dir_contents.contains(exp_inode)); - exp_dir_contents.remove(exp_inode); + for (var i = 0; i < exp_dir_contents.len(); ++i) { + var exp_inode = exp_dir_contents[i]; + assert(dir_contents.contains(exp_inode)); + exp_dir_contents.remove(exp_inode); + } } From 8698e11220f6b9f5320dd395276c4eb9a7d5fbe7 Mon Sep 17 00:00:00 2001 From: vnksnkr Date: Sun, 11 Oct 2020 11:30:04 +0530 Subject: [PATCH 52/61] add string.split function for empty string delimiters --- c/datatypes/strings.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/c/datatypes/strings.c b/c/datatypes/strings.c index b6fd7def..451737d7 100644 --- a/c/datatypes/strings.c +++ b/c/datatypes/strings.c @@ -135,7 +135,20 @@ static Value splitString(VM *vm, int argCount, Value *args) { ObjList *list = initList(vm); push(vm, OBJ_VAL(list)); - + if(!strcmp(AS_CSTRING(args[1]),"")) + { + for(int tokencount=0;tokencountlength;tokencount++) + { + *(tmp)=string->chars[tokencount]; + *(tmp+1)='\0'; + Value str = OBJ_VAL(copyString(vm, tmp, strlen(tmp))); + // Push to stack to avoid GC + push(vm, str); + writeValueArray(vm, &list->values, str); + pop(vm); + } + } +else{ do { token = strstr(tmp, delimiter); if (token) @@ -150,6 +163,7 @@ static Value splitString(VM *vm, int argCount, Value *args) { tmp = token + delimiterLength; } while (token != NULL); + } pop(vm); free(tmpFree); From 0a7f381ebbfc517b8b11879c49712fa035030bb1 Mon Sep 17 00:00:00 2001 From: vnksnkr Date: Sun, 11 Oct 2020 18:28:17 +0530 Subject: [PATCH 53/61] add string.split for empty string delimiters --- c/datatypes/strings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/datatypes/strings.c b/c/datatypes/strings.c index 451737d7..28daac85 100644 --- a/c/datatypes/strings.c +++ b/c/datatypes/strings.c @@ -135,7 +135,7 @@ static Value splitString(VM *vm, int argCount, Value *args) { ObjList *list = initList(vm); push(vm, OBJ_VAL(list)); - if(!strcmp(AS_CSTRING(args[1]),"")) + if(!strlen(delimiter)) { for(int tokencount=0;tokencountlength;tokencount++) { From b58f58b9298abd78e9a745c7ebb32dc5616a70bc Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Sun, 11 Oct 2020 14:22:35 +0100 Subject: [PATCH 54/61] Code formatting changes and update if condition for empty delimiter --- c/datatypes/strings.c | 69 ++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/c/datatypes/strings.c b/c/datatypes/strings.c index 28daac85..0fe69f33 100644 --- a/c/datatypes/strings.c +++ b/c/datatypes/strings.c @@ -40,7 +40,7 @@ static Value formatString(VM *vm, int argCount, Value *args) { } int length = 0; - char **replaceStrings = malloc(argCount * sizeof(char*)); + char **replaceStrings = malloc(argCount * sizeof(char *)); for (int j = 1; j < argCount + 1; j++) { Value value = args[j]; @@ -64,8 +64,7 @@ static Value formatString(VM *vm, int argCount, Value *args) { memcpy(tmp, string->chars, stringLen); int count = 0; - while((tmp = strstr(tmp, "{}"))) - { + while ((tmp = strstr(tmp, "{}"))) { count++; tmp++; } @@ -135,34 +134,31 @@ static Value splitString(VM *vm, int argCount, Value *args) { ObjList *list = initList(vm); push(vm, OBJ_VAL(list)); - if(!strlen(delimiter)) - { - for(int tokencount=0;tokencountlength;tokencount++) - { - *(tmp)=string->chars[tokencount]; - *(tmp+1)='\0'; - Value str = OBJ_VAL(copyString(vm, tmp, strlen(tmp))); - // Push to stack to avoid GC - push(vm, str); - writeValueArray(vm, &list->values, str); - pop(vm); - } - } -else{ - do { - token = strstr(tmp, delimiter); - if (token) - *token = '\0'; - - Value str = OBJ_VAL(copyString(vm, tmp, strlen(tmp))); - - // Push to stack to avoid GC - push(vm, str); - writeValueArray(vm, &list->values, str); - pop(vm); - - tmp = token + delimiterLength; - } while (token != NULL); + if (delimiterLength == 0) { + for (int tokenCount = 0; tokenCount < string->length; tokenCount++) { + *(tmp) = string->chars[tokenCount]; + *(tmp + 1) = '\0'; + Value str = OBJ_VAL(copyString(vm, tmp, 1)); + // Push to stack to avoid GC + push(vm, str); + writeValueArray(vm, &list->values, str); + pop(vm); + } + } else { + do { + token = strstr(tmp, delimiter); + if (token) + *token = '\0'; + + Value str = OBJ_VAL(copyString(vm, tmp, strlen(tmp))); + + // Push to stack to avoid GC + push(vm, str); + writeValueArray(vm, &list->values, str); + pop(vm); + + tmp = token + delimiterLength; + } while (token != NULL); } pop(vm); @@ -261,7 +257,7 @@ static Value replaceString(VM *vm, int argCount, Value *args) { // Count the occurrences of the needle so we can determine the size // of the string we need to allocate - while((tmp = strstr(tmp, to_replace->chars)) != NULL) { + while ((tmp = strstr(tmp, to_replace->chars)) != NULL) { count++; tmp += len; } @@ -309,7 +305,7 @@ static Value lowerString(VM *vm, int argCount, Value *args) { char *temp = malloc(sizeof(char) * (string->length + 1)); - for(int i = 0; string->chars[i]; i++){ + for (int i = 0; string->chars[i]; i++) { temp[i] = tolower(string->chars[i]); } temp[string->length] = '\0'; @@ -322,14 +318,14 @@ static Value lowerString(VM *vm, int argCount, Value *args) { static Value upperString(VM *vm, int argCount, Value *args) { if (argCount != 0) { runtimeError(vm, "upper() takes no arguments (%d given)", argCount); - return EMPTY_VAL ; + return EMPTY_VAL; } ObjString *string = AS_STRING(args[0]); char *temp = malloc(sizeof(char) * (string->length + 1)); - for(int i = 0; string->chars[i]; i++){ + for (int i = 0; string->chars[i]; i++) { temp[i] = toupper(string->chars[i]); } temp[string->length] = '\0'; @@ -450,8 +446,7 @@ static Value countString(VM *vm, int argCount, Value *args) { char *needle = AS_CSTRING(args[1]); int count = 0; - while((haystack = strstr(haystack, needle))) - { + while ((haystack = strstr(haystack, needle))) { count++; haystack++; } From 4ce8ecd5d4d5a387556bfbe39217b2b3240b16ee Mon Sep 17 00:00:00 2001 From: vnksnkr Date: Sun, 11 Oct 2020 21:32:48 +0530 Subject: [PATCH 55/61] add tests and documentation for string.split --- docs/docs/strings.md | 5 +++-- tests/strings/split.du | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/docs/strings.md b/docs/docs/strings.md index 179879b9..bec0f7b0 100644 --- a/docs/docs/strings.md +++ b/docs/docs/strings.md @@ -165,9 +165,10 @@ Returns true if a string ends with a given string. ### string.split(delimiter) Returns a list of strings, split based on a given delimiter. - +Returns a list of all characters in a string if an empty string is passed as delimiter. ```cs "Dictu is awesome!".split(" "); // ['Dictu', 'is', 'awesome!'] +"Dictu is awesome!".split(""); // ["D", "i", "c", "t", "u", " ", "i", "s", " ", "a", "w", "e", "s", "o", "m", "e", "!"] ``` ### string.replace(string: old, string: new) @@ -240,4 +241,4 @@ Returns the number of occurrences of a given substring within another string. "Dictu is great!".count("Dictu"); // 1 "This documentation".count("Good jokes"); // 0 "Sooooooooooome characters".count("o"); // 11 -``` \ No newline at end of file +``` diff --git a/tests/strings/split.du b/tests/strings/split.du index 517bf6dc..c28deb29 100644 --- a/tests/strings/split.du +++ b/tests/strings/split.du @@ -12,4 +12,5 @@ assert("Dictu--is--great!".split("--") == ["Dictu", "is", "great!"]); assert("Dictuisgreat!".split("") == ["Dictu", "is", "great!"]); assert("Dictu is great!".split(",") == ["Dictu is great!"]); assert("Dictu is great!".split("12345") == ["Dictu is great!"]); -assert("Dictu is great!".split("!@£$%^") == ["Dictu is great!"]); \ No newline at end of file +assert("Dictu is great!".split("!@£$%^") == ["Dictu is great!"]); +assert("Dictu is great!".split("") == ["D", "i", "c", "t", "u", " ", "i", "s", " ", "g", "r", "e", "a", "t", "!"]); From 0ce87d2b4967f998e6f8a17afdf089d575447ab4 Mon Sep 17 00:00:00 2001 From: The Great Cookie Machine <39784551+TheGreatCookieMachine@users.noreply.github.com> Date: Sun, 11 Oct 2020 13:16:27 -0700 Subject: [PATCH 56/61] Port Path.listdir to Windows --- c/optionals/path.c | 37 +++++++++++++++++++++++++++++++++---- c/optionals/path.h | 2 ++ tests/path/import.du | 3 ++- tests/path/listdir.du | 15 ++++++--------- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/c/optionals/path.c b/c/optionals/path.c index 23f959fc..a92bb0c4 100644 --- a/c/optionals/path.c +++ b/c/optionals/path.c @@ -194,7 +194,6 @@ static Value isdirNative(VM *vm, int argCount, Value *args) { } -#ifndef _WIN32 static Value listdirNative(VM *vm, int argCount, Value *args) { if (argCount > 1) { runtimeError(vm, "listdir() takes 0 or 1 arguments (%d given)", argCount); @@ -214,6 +213,38 @@ static Value listdirNative(VM *vm, int argCount, Value *args) { ObjList *dir_contents = initList(vm); push(vm, OBJ_VAL(dir_contents)); + + #ifdef _WIN32 + char *searchPath = malloc(strlen(path) + 4); + if (searchPath == NULL) { + runtimeError(vm, "Memory error on listdir()!"); + return EMPTY_VAL; + } + strcpy(searchPath, path); + strcat(searchPath, "\\*"); + + WIN32_FIND_DATAA file; + HANDLE dir = FindFirstFile(searchPath, &file); + if (dir == INVALID_HANDLE_VALUE) { + runtimeError(vm, "%s is not a path!", path); + free(searchPath); + return EMPTY_VAL; + } + + do { + if (strcmp(file.cFileName, ".") == 0 || strcmp(file.cFileName, "..") == 0) { + continue; + } + + Value fileName = OBJ_VAL(copyString(vm, file.cFileName, strlen(file.cFileName))); + push(vm, fileName); + writeValueArray(vm, &dir_contents->values, fileName); + pop(vm); + } while (FindNextFile(dir, &file) != 0); + + FindClose(dir); + free(searchPath); + #else struct dirent *dir; DIR *d; d = opendir(path); @@ -231,12 +262,12 @@ static Value listdirNative(VM *vm, int argCount, Value *args) { runtimeError(vm, "%s is not a path!", path); return EMPTY_VAL; } + #endif pop(vm); return OBJ_VAL(dir_contents); } -#endif ObjModule *createPathClass(VM *vm) { ObjString *name = copyString(vm, "Path", 4); @@ -258,9 +289,7 @@ ObjModule *createPathClass(VM *vm) { defineNative(vm, &module->values, "dirname", dirnameNative); defineNative(vm, &module->values, "exists", existsNative); defineNative(vm, &module->values, "isdir", isdirNative); -#ifndef _WIN32 defineNative(vm, &module->values, "listdir", listdirNative); -#endif defineNativeProperty(vm, &module->values, "delimiter", OBJ_VAL( copyString(vm, PATH_DELIMITER_AS_STRING, PATH_DELIMITER_STRLEN))); diff --git a/c/optionals/path.h b/c/optionals/path.h index d6ff9e6b..a879ee62 100644 --- a/c/optionals/path.h +++ b/c/optionals/path.h @@ -10,6 +10,8 @@ #endif #ifdef _WIN32 +#include "../windowsapi.h" + #define DIR_SEPARATOR '\\' #define DIR_ALT_SEPARATOR '/' #define DIR_SEPARATOR_AS_STRING "\\" diff --git a/tests/path/import.du b/tests/path/import.du index d9f0581b..68c28030 100644 --- a/tests/path/import.du +++ b/tests/path/import.du @@ -10,4 +10,5 @@ import "tests/path/extname.du"; import "tests/path/isAbsolute.du"; import "tests/path/realpath.du"; import "tests/path/exists.du"; -import "tests/path/isdir.du"; \ No newline at end of file +import "tests/path/isdir.du"; +import "tests/path/listdir.du"; \ No newline at end of file diff --git a/tests/path/listdir.du b/tests/path/listdir.du index e1950aa7..37c733bd 100644 --- a/tests/path/listdir.du +++ b/tests/path/listdir.du @@ -6,13 +6,10 @@ */ import Path; -if (System.platform != 'windows') { - var dir_contents = Path.listdir("tests/path/test_dir"); - var exp_dir_contents = ["test_file_1", "test_file_2", "test_file_3"]; - - for (var i = 0; i < exp_dir_contents.len(); ++i) { - var exp_inode = exp_dir_contents[i]; - assert(dir_contents.contains(exp_inode)); - exp_dir_contents.remove(exp_inode); - } +var dir_contents = Path.listdir("tests/path/test_dir"); +var exp_dir_contents = ["test_file_1", "test_file_2", "test_file_3"]; +for (var i = 0; i < exp_dir_contents.len(); ++i) { + var exp_inode = exp_dir_contents[i]; + assert(dir_contents.contains(exp_inode)); + exp_dir_contents.remove(exp_inode); } From 772a46aaa19dd14e1dbe78c1ceb9bff1ff9d3b92 Mon Sep 17 00:00:00 2001 From: The Great Cookie Machine <39784551+TheGreatCookieMachine@users.noreply.github.com> Date: Sun, 11 Oct 2020 13:17:57 -0700 Subject: [PATCH 57/61] Correct Path.listdir documentation --- docs/docs/path.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/docs/path.md b/docs/docs/path.md index 5a7a73b5..b0f08ed5 100644 --- a/docs/docs/path.md +++ b/docs/docs/path.md @@ -109,8 +109,6 @@ Returns a list of strings containing the contents of the input path. **Note:** This function does not guarantee any ordering of the returned list. -**Note:** This is not available on windows systems. - ```js Path.listdir("/"); // ["bin", "dev", "home", "lib", ...] ``` From 97ffe85a3890896c2298bd612d956a370f86732c Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Mon, 12 Oct 2020 20:00:48 +0100 Subject: [PATCH 58/61] Decrease cmake version and gitignore build directories --- .gitignore | 5 ++++- CMakeLists.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7e6055ef..a4e97f4c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,7 @@ venv/ cmake-build-debug/CMakeFiles/clion-log.txt docs/.jekyll-cache/ -docs/_site/ \ No newline at end of file +docs/_site/ +cmake-build-debug/ + +cmake-build-release/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 554ab734..1016dd7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.18.0) +cmake_minimum_required(VERSION 3.16.5) project(Dictu C) set(CMAKE_C_STANDARD 11) From 461c4e3f8d0b1732f98dbde879ddee04dfa1d8e3 Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Sat, 17 Oct 2020 22:11:35 +0100 Subject: [PATCH 59/61] Add CMake + windows OS to the CI process. Add CMake build instructions --- .github/workflows/main.yml | 124 +++++++++++++++++++++++++++---------- CMakeLists.txt | 2 +- README.md | 42 ++++++++++++- docs/index.md | 13 +++- tests/system/setCWD.du | 2 +- 5 files changed, 146 insertions(+), 37 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 12e588ba..4c7857f0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,45 +7,105 @@ on: - master jobs: - test-ubuntu: - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, ubuntu-16.04, ubuntu-20.04] + test-ubuntu: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, ubuntu-16.04, ubuntu-20.04] - steps: - - uses: actions/checkout@v2 - - name: Make dictu and run tests (No HTTP) - run: | - make debug DISABLE_HTTP=1 - ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' - - name: Remove build directory - run: | - rm -rf build - - name: Make dictu and run tests (HTTP) - run: | - sudo apt-get update - sudo apt-get install -y libcurl4-openssl-dev - make debug - ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' - test-mac: + steps: + - uses: actions/checkout@v2 + - name: Make dictu and run tests (No HTTP) + run: | + make debug DISABLE_HTTP=1 + ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + - name: Remove build directory + run: | + rm -rf build + - name: Make dictu and run tests (HTTP) + run: | + sudo apt-get update + sudo apt-get install -y libcurl4-openssl-dev + make debug + ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + test-ubuntu-cmake: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, ubuntu-16.04, ubuntu-20.04] + + steps: + - uses: actions/checkout@v2 + - name: Make dictu and run tests (No HTTP) + run: | + cmake -DCMAKE_BUILD_TYPE=Debug -DDISABLE_HTTP=1 -B ./build + cmake --build ./build + ./build/Dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + - name: Remove build directory + run: | + rm -rf build + - name: Make dictu and run tests (HTTP) + run: | + sudo apt-get update + sudo apt-get install -y libcurl4-openssl-dev + cmake -DCMAKE_BUILD_TYPE=Debug -B ./build + cmake --build ./build + ./build/Dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + test-mac: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macOS-latest] + + steps: + - uses: actions/checkout@v2 + - name: Make dictu and run tests (No HTTP) + run: | + make debug DISABLE_HTTP=1 + ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + - name: Remove build directory + run: | + rm -rf build + - name: Make dictu and run tests + run: | + make debug + ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + test-mac-cmake: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macOS-latest] + + steps: + - uses: actions/checkout@v2 + - name: Make dictu and run tests (No HTTP) + run: | + cmake -DCMAKE_BUILD_TYPE=Debug -DDISABLE_HTTP=1 -B ./build + cmake --build ./build + ./build/Dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + - name: Remove build directory + run: | + rm -rf build + - name: Make dictu and run tests + run: | + cmake -DCMAKE_BUILD_TYPE=Debug -B ./build + cmake --build ./build + ./build/Dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + test-windows-cmake: name: Test on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: - os: [macOS-latest] + os: [windows-2019, windows-latest] steps: - uses: actions/checkout@v2 - name: Make dictu and run tests (No HTTP) run: | - make debug DISABLE_HTTP=1 - ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' - - name: Remove build directory - run: | - rm -rf build - - name: Make dictu and run tests - run: | - make debug - ./dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' + cmake -DCMAKE_BUILD_TYPE=Debug -DDISABLE_HTTP=1 -DDISABLE_LINENOISE=1 -B build + cmake --build build + build\Debug\Dictu.exe tests/runTests.du \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1016dd7c..5c467f03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(Dictu C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_C_EXTENSIONS OFF) +set(CMAKE_C_EXTENSIONS ON) set(DISABLE_HTTP OFF CACHE BOOL "Determines if HTTPS based features are compiled. HTTPS based features require cURL.") set(DISABLE_LINENOISE OFF CACHE BOOL "Determines if the REPL uses linenoise. Linenoise requires termios.") diff --git a/README.md b/README.md index 2bf7b113..1aac2aec 100644 --- a/README.md +++ b/README.md @@ -20,14 +20,52 @@ Dictu means `simplistic` in Latin. Documentation for Dictu can be found [here](https://dictu-lang.com/) ## Running Dictu +Dictu currently has two options when building, there is a CMakeLists file included so the build files can be generated with +CMake or there is an included makefile for users that are more familiar with that. + +### CMake ```bash -$ git clone https://github.com/Jason2605/Dictu.git +$ git clone https://github.com/dictu-lang/Dictu.git +$ cd Dictu +$ cmake -DCMAKE_BUILD_TYPE=Release -B ./build +$ cmake --build ./build +$ ./build/Dictu +``` + +#### Compiling without HTTP + +The HTTP class within Dictu requires [cURL](https://curl.haxx.se/) to be installed when building the interpreter. If you wish to +build Dictu without cURL, and in turn the HTTP class, build with the `DISABLE_HTTP` flag. + +```bash +$ git clone https://github.com/dictu-lang/Dictu.git +$ cd Dictu +$ cmake -DCMAKE_BUILD_TYPE=Release -DDISABLE_HTTP=1 -B ./build +$ cmake --build ./build +$ ./build/Dictu +``` + +#### Compiling without linenoise +[Linenoise](https://github.com/antirez/linenoise) is used within Dictu to enhance the REPL, however it does not build on windows +systems so a simpler REPL solution is used. + +```bash +$ git clone https://github.com/dictu-lang/Dictu.git +$ cd Dictu +$ cmake -DCMAKE_BUILD_TYPE=Release -DDISABLE_LINENOISE=1 -B ./build +$ cmake --build ./build +$ ./build/Dictu +``` + +### Makefile +```bash +$ git clone https://github.com/dictu-lang/Dictu.git $ cd Dictu $ make dictu $ ./dictu examples/guessingGame.du ``` -### Compiling without HTTP +#### Compiling without HTTP The HTTP class within Dictu requires [cURL](https://curl.haxx.se/) to be installed when building the interpreter. If you wish to build Dictu without cURL, and in turn the HTTP class, build with the `DISABLE_HTTP` flag. diff --git a/docs/index.md b/docs/index.md index 2655ed6e..97c2bf9d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -31,8 +31,19 @@ Dictu means simplistic in Latin. This is the aim of the language: to be as simpl --- ## Installing Dictu +All it takes is a couple of lines! Fire up a terminal and copy the following, one by one (without the $). -All it takes is three lines! Fire up a terminal and copy the following, one by one (without the $). +### CMake + +```bash +$ git clone https://github.com/dictu-lang/Dictu.git +$ cd Dictu +$ cmake -DCMAKE_BUILD_TYPE=Release -B ./build +$ cmake --build ./build +$ ./build/Dictu +``` + +### Makefile ```bash $ git clone https://github.com/dictu-lang/Dictu.git diff --git a/tests/system/setCWD.du b/tests/system/setCWD.du index 10da8a8d..39c4f283 100644 --- a/tests/system/setCWD.du +++ b/tests/system/setCWD.du @@ -12,7 +12,7 @@ assert(type(cwd) == "string"); assert(cwd.len() > 0); assert(System.setCWD("/") == 0); if (System.platform == "windows") { - assert(System.getCWD() == "C:\\"); + assert(System.getCWD() == "C:\\" or System.getCWD() == "D:\\"); } else { assert(System.getCWD() == "/"); } From bb5b76db0291f396f8de8479d4882a4615c72bd2 Mon Sep 17 00:00:00 2001 From: Jason_000 Date: Sat, 17 Oct 2020 22:14:41 +0100 Subject: [PATCH 60/61] Fix syntax issue in the actions config --- .github/workflows/main.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4c7857f0..6f77f9ed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -95,17 +95,17 @@ jobs: cmake -DCMAKE_BUILD_TYPE=Debug -B ./build cmake --build ./build ./build/Dictu tests/runTests.du | tee /dev/stderr | grep -q 'Total memory usage: 0' - test-windows-cmake: - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [windows-2019, windows-latest] + test-windows-cmake: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-2019, windows-latest] - steps: - - uses: actions/checkout@v2 - - name: Make dictu and run tests (No HTTP) - run: | - cmake -DCMAKE_BUILD_TYPE=Debug -DDISABLE_HTTP=1 -DDISABLE_LINENOISE=1 -B build - cmake --build build - build\Debug\Dictu.exe tests/runTests.du \ No newline at end of file + steps: + - uses: actions/checkout@v2 + - name: Make dictu and run tests (No HTTP No Linenoise) + run: | + cmake -DCMAKE_BUILD_TYPE=Debug -DDISABLE_HTTP=1 -DDISABLE_LINENOISE=1 -B build + cmake --build build + build\Debug\Dictu.exe tests/runTests.du \ No newline at end of file From 5463d4749207b9bb64b41f83833d875481342e6e Mon Sep 17 00:00:00 2001 From: Jason Hall Date: Tue, 20 Oct 2020 12:51:09 +0100 Subject: [PATCH 61/61] Bump version to 0.11.0 --- c/main.c | 2 +- docs/_config.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/main.c b/c/main.c index 68074a6a..bb4abcff 100644 --- a/c/main.c +++ b/c/main.c @@ -18,7 +18,7 @@ void cleanupSockets(void) { #include "vm.h" #include "util.h" -#define VERSION "Dictu Version: 0.10.0\n" +#define VERSION "Dictu Version: 0.11.0\n" #ifndef DISABLE_LINENOISE #include "linenoise.h" diff --git a/docs/_config.yml b/docs/_config.yml index cebd9b32..7eeb72cb 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -5,7 +5,7 @@ description: >- color_scheme: "dictu" # Custom theme logo: "/assets/images/dictu-logo/dictu-wordmark.svg" -version: "0.10.0" +version: "0.11.0" github_username: dictu-lang search_enabled: true