diff options
Diffstat (limited to 'tests/custom/04_modules')
-rw-r--r-- | tests/custom/04_modules/01_export_variable_declaration | 29 | ||||
-rw-r--r-- | tests/custom/04_modules/02_export_function_declaration | 22 | ||||
-rw-r--r-- | tests/custom/04_modules/03_export_list | 27 | ||||
-rw-r--r-- | tests/custom/04_modules/04_export_rename | 28 | ||||
-rw-r--r-- | tests/custom/04_modules/05_export_default | 38 | ||||
-rw-r--r-- | tests/custom/04_modules/06_export_errors | 89 | ||||
-rw-r--r-- | tests/custom/04_modules/07_import_default | 99 | ||||
-rw-r--r-- | tests/custom/04_modules/08_import_list | 105 | ||||
-rw-r--r-- | tests/custom/04_modules/09_import_wildcard | 73 | ||||
-rw-r--r-- | tests/custom/04_modules/10_import_none | 18 | ||||
-rw-r--r-- | tests/custom/04_modules/11_import_many_exec_once | 28 | ||||
-rw-r--r-- | tests/custom/04_modules/12_import_immutability | 52 | ||||
-rw-r--r-- | tests/custom/04_modules/13_import_liveness | 29 |
13 files changed, 637 insertions, 0 deletions
diff --git a/tests/custom/04_modules/01_export_variable_declaration b/tests/custom/04_modules/01_export_variable_declaration new file mode 100644 index 0000000..19a1c11 --- /dev/null +++ b/tests/custom/04_modules/01_export_variable_declaration @@ -0,0 +1,29 @@ +Variable declarations can be prepended with `export` to automatically +export each variable using the same name as the variable itself. + +Updates to the variable after the export are reflected properly in +the including scope. + +-- File test-var-decl.uc -- +export let a, b, c; +export let d = 4, e = 5, f = 6; +export const g = 7, h = 8, i = 9; + +a = 1; +b = 2; +c = 3; +-- End -- + +-- Testcase -- +import { a, b, c, d, e, f, g, h, i } from "./files/test-var-decl.uc"; + +print([ a, b, c, d, e, f, g, h, i ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] +-- End -- diff --git a/tests/custom/04_modules/02_export_function_declaration b/tests/custom/04_modules/02_export_function_declaration new file mode 100644 index 0000000..4067da9 --- /dev/null +++ b/tests/custom/04_modules/02_export_function_declaration @@ -0,0 +1,22 @@ +A named function declaration can be prepended with `export` to +automatically export the function. + +-- File test-func-decl.uc -- +export function func() { + print("Hello, world!\n"); +}; +-- End -- + +-- Testcase -- +import { func } from "./files/test-func-decl.uc"; + +func(); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +Hello, world! +-- End -- diff --git a/tests/custom/04_modules/03_export_list b/tests/custom/04_modules/03_export_list new file mode 100644 index 0000000..8f93f08 --- /dev/null +++ b/tests/custom/04_modules/03_export_list @@ -0,0 +1,27 @@ +Already declared local variables and functions may be exported using the +curly brace export list syntax. + +-- File test-var-decl.uc -- +let testvar = 123; +const testconst = "Test"; + +function testfunc() { + print("Hello, world!\n"); +} + +export { testvar, testconst, testfunc }; +-- End -- + +-- Testcase -- +import { testvar, testconst, testfunc } from "./files/test-var-decl.uc"; + +print([ testvar, testconst, testfunc ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 123, "Test", "function testfunc() { ... }" ] +-- End -- diff --git a/tests/custom/04_modules/04_export_rename b/tests/custom/04_modules/04_export_rename new file mode 100644 index 0000000..49057fd --- /dev/null +++ b/tests/custom/04_modules/04_export_rename @@ -0,0 +1,28 @@ +By using the `as` keyword, exports may be renamed when using the export +list syntax. It is also possible to specify string aliases which are not +valid variable names, in this case a rename on import is mandatory. + +-- File test.uc -- +let testvar = 123; +const testconst = "Test"; + +function testfunc() { + print("Hello, world!\n"); +} + +export { testvar as modvar, testconst as 'define', testfunc as "module-function" }; +-- End -- + +-- Testcase -- +import { modvar, define, "module-function" as func } from "./files/test.uc"; + +print([ modvar, define, func ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 123, "Test", "function testfunc() { ... }" ] +-- End -- diff --git a/tests/custom/04_modules/05_export_default b/tests/custom/04_modules/05_export_default new file mode 100644 index 0000000..a4c8a43 --- /dev/null +++ b/tests/custom/04_modules/05_export_default @@ -0,0 +1,38 @@ +The `export default` statement can be used to declare a default export +value for a module. The value for `export default` can be an arbitrary +expression, it must not refer to a local variable. + +When using the export list syntax, the alias "default" can be used to +designate the default export. + +-- File test-default-expr.uc -- +export default 7 * 21; +-- End -- + +-- File test-default-func.uc -- +export default function() { + return "Hello, world!"; +}; +-- End -- + +-- File test-default-alias.uc -- +let a = 1, b = 2, c = 3; + +export { a, b as default, c }; +-- End -- + +-- Testcase -- +import def1 from "./files/test-default-expr.uc"; +import def2 from "./files/test-default-func.uc"; +import def3 from "./files/test-default-alias.uc"; + +print([ def1, def2(), def3 ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 147, "Hello, world!", 2 ] +-- End -- diff --git a/tests/custom/04_modules/06_export_errors b/tests/custom/04_modules/06_export_errors new file mode 100644 index 0000000..c02a547 --- /dev/null +++ b/tests/custom/04_modules/06_export_errors @@ -0,0 +1,89 @@ +Export statements are only allowed at the toplevel of a module. + +-- Testcase -- +export let x = 1; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Exports may only appear at top level of a module + + `export let x = 1;` + ^-- Near here + + +-- End -- + + +Export statements are not allowed within functions or nested blocks. + +-- Testcase -- +import "./files/test.uc"; +-- End -- + +-- File test.uc -- +{ + export let x = 1; +} +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unable to compile module './files/test.uc': +Syntax error: Exports may only appear at top level of a module +In line 2, byte 2: + + ` export let x = 1;` + ^-- Near here + + + +In line 1, byte 25: + + `import "./files/test.uc";` + Near here --------------^ + + +-- End -- + + +Duplicate export names should result in an error. + +-- Testcase -- +import "./files/test-duplicate.uc"; +-- End -- + +-- File test-duplicate.uc -- +let x = 1, y = 2; + +export { x }; +export { y as x }; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unable to compile module './files/test-duplicate.uc': +Syntax error: Duplicate export 'x' for module './files/test-duplicate.uc' +In line 4, byte 15: + + `export { y as x };` + Near here ----^ + + + +In line 1, byte 35: + + `import "./files/test-duplicate.uc";` + Near here ------------------------^ + + +-- End -- diff --git a/tests/custom/04_modules/07_import_default b/tests/custom/04_modules/07_import_default new file mode 100644 index 0000000..7190a22 --- /dev/null +++ b/tests/custom/04_modules/07_import_default @@ -0,0 +1,99 @@ +An `import` statement with a sole label will import the modules default +export and bind it to a local variable named after the label. + +-- Testcase -- +import defVal from "./files/test1.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test1.uc -- +export default "This is the default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +This is the default export +-- End -- + + +Attemping to import a default export from a module without default +export will raise an error. + +-- Testcase -- +import defVal from "./files/test2.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test2.uc -- +export const x = "This is a non-default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Module ./files/test2.uc has no default export +In line 1, byte 20: + + `import defVal from "./files/test2.uc";` + Near here ---------^ + + +-- End -- + + +In import statements usign the list syntax, the `default` keyword can be +used to refer to default exports. + +-- Testcase -- +import { default as defVal } from "./files/test3.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test3.uc -- +export default "This is the default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +This is the default export +-- End -- + + +When using the default keyword within the list syntax, the `as` keyword is +mandatory to assign a non-reserved keyword as name. + +-- Testcase -- +import { default } from "./files/test4.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test4.uc -- +export default "This is the default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unexpected token +Expecting 'as' +In line 1, byte 18: + + `import { default } from "./files/test4.uc";` + Near here -------^ + + +-- End -- diff --git a/tests/custom/04_modules/08_import_list b/tests/custom/04_modules/08_import_list new file mode 100644 index 0000000..1a4f116 --- /dev/null +++ b/tests/custom/04_modules/08_import_list @@ -0,0 +1,105 @@ +An `import` statement followed by a curly brace enclosed list of names +will import the corresponding exports from the module. + +-- Testcase -- +import { a, b, c } from "./files/test1.uc"; + +print([ a, b, c ], "\n"); +-- End -- + +-- File test1.uc -- +export const a = 1, b = 2, c = 3; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 1, 2, 3 ] +-- End -- + + +Attemping to import a not exported name will raise an error. + +-- Testcase -- +import y from "./files/test2.uc"; + +print(y, "\n"); +-- End -- + +-- File test2.uc -- +export const x = "This is a test"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Module ./files/test2.uc has no default export +In line 1, byte 15: + + `import y from "./files/test2.uc";` + Near here ----^ + + +-- End -- + + +Imports may be renamed to assign an alternative local name to the +exported module symbols. Renaming is also required for string export +names which are no valid variable identifiers. + +-- Testcase -- +import { a as var1, bool as var2, "my function" as var3 } from "./files/test3.uc"; + +print([ var1, var2, var3 ], "\n"); +-- End -- + +-- File test3.uc -- +const a = "A string"; + +let b = 123; + +function c() { + return "A function" +} + +export { + a, + b as bool, + c as "my function" +}; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ "A string", 123, "function c() { ... }" ] +-- End -- + + +A list expression may follow a default import expression in an `import` +statment. + +-- Testcase -- +import defVal, { a as x, b as y, c as z } from "./files/test4.uc"; + +print([defVal, x, y, z], "\n"); +-- End -- + +-- File test4.uc -- +export const a = 1, b = 2, c = 3; +export default a + b + c; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 6, 1, 2, 3 ] +-- End -- diff --git a/tests/custom/04_modules/09_import_wildcard b/tests/custom/04_modules/09_import_wildcard new file mode 100644 index 0000000..aa3dc82 --- /dev/null +++ b/tests/custom/04_modules/09_import_wildcard @@ -0,0 +1,73 @@ +By specifying `*` instead of a label or an import list after an `import` +keyword, all of the modules exports are aggregated into an object whose +keys and values refer to the exported names and their corresponding +values respectively. + +-- Testcase -- +import * as mod from "./files/test1.uc"; + +print(mod, "\n"); +-- End -- + +-- File test1.uc -- +export const a = 1, b = 2, c = 3; +export default a + b + c; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +{ "a": 1, "b": 2, "c": 3, "default": 6 } +-- End -- + + +When using the wildcard import syntax, assigning a name using the `as` +expression is mandatory. + +-- Testcase -- +import * from "./files/test2.uc"; +-- End -- + +-- File test2.uc -- +export const x = "This is a test"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unexpected token +Expecting 'as' +In line 1, byte 10: + + `import * from "./files/test2.uc";` + ^-- Near here + + +-- End -- + + +A wildcard expression may follow a default import expression in an `import` +statment. + +-- Testcase -- +import defVal, * as mod from "./files/test3.uc"; + +print([defVal, mod], "\n"); +-- End -- + +-- File test3.uc -- +export const a = 1, b = 2, c = 3; +export default a + b + c; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 6, { "a": 1, "b": 2, "c": 3, "default": 6 } ] +-- End -- diff --git a/tests/custom/04_modules/10_import_none b/tests/custom/04_modules/10_import_none new file mode 100644 index 0000000..be30106 --- /dev/null +++ b/tests/custom/04_modules/10_import_none @@ -0,0 +1,18 @@ +An `import` statement may omit a default name, wildcard expression or name +lsit entirely to execute a module code solely for its side effects. + +-- Testcase -- +import "./files/test.uc"; +-- End -- + +-- File test.uc -- +print("This is the test module running\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +This is the test module running +-- End -- diff --git a/tests/custom/04_modules/11_import_many_exec_once b/tests/custom/04_modules/11_import_many_exec_once new file mode 100644 index 0000000..f469c7f --- /dev/null +++ b/tests/custom/04_modules/11_import_many_exec_once @@ -0,0 +1,28 @@ +When multiple imports refer to the same module, the module will only be +executed once. The equivalence of module paths is tested after canonicalizing +the requested path. + +-- Testcase -- +import { counter as counter1 } from "./files/test/example.uc"; +import { counter as counter2 } from "files/test/example.uc"; +import { counter as counter3 } from "test.example"; + +print([ counter1, counter2, counter3 ], "\n"); +-- End -- + +-- File test/example.uc -- +print("This is the test module running\n"); + +export let counter = 0; + +counter++; +-- End -- + +-- Args -- +-R -L ./files +-- End -- + +-- Expect stdout -- +This is the test module running +[ 1, 1, 1 ] +-- End -- diff --git a/tests/custom/04_modules/12_import_immutability b/tests/custom/04_modules/12_import_immutability new file mode 100644 index 0000000..37c0bc6 --- /dev/null +++ b/tests/custom/04_modules/12_import_immutability @@ -0,0 +1,52 @@ +Module imports are read-only bindings to the exported module variables. + +-- Testcase -- +import { a } from "./files/test.uc"; + +a = 2; +-- End -- + +-- File test.uc -- +export let a = 1; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Invalid assignment to constant 'a' +In line 3, byte 5: + + `a = 2;` + ^-- Near here + + +-- End -- + + +Aggregated module objects are read-only as well. + +-- Testcase -- +import * as mod from "./files/test.uc"; + +mod.a = 2; +-- End -- + +-- File test.uc -- +export let a = 1; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Type error: object value is immutable +In line 3, byte 9: + + `mod.a = 2;` + ^-- Near here + + +-- End -- diff --git a/tests/custom/04_modules/13_import_liveness b/tests/custom/04_modules/13_import_liveness new file mode 100644 index 0000000..ca7ff35 --- /dev/null +++ b/tests/custom/04_modules/13_import_liveness @@ -0,0 +1,29 @@ +Imported bindings to exported module variables are live, they'll reflect +every change to the exported variable values. + +-- Testcase -- +import { counter, count } from "./files/test.uc"; + +print(counter, "\n"); +count(); +print(counter, "\n"); +-- End -- + +-- File test.uc -- +let counter = 1; + +function count() { + counter++; +} + +export { counter, count }; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +1 +2 +-- End -- |