upload code
This commit is contained in:
commit
3f507064ce
111 changed files with 9258 additions and 0 deletions
7
integration/fail/no-such-field/assignment-bool-field.out
Normal file
7
integration/fail/no-such-field/assignment-bool-field.out
Normal file
|
@ -0,0 +1,7 @@
|
|||
Error: No such field
|
||||
╭─[assignment-bool-field.txt:2:5]
|
||||
│
|
||||
2 │ foo.bar = true;
|
||||
· ─┬─
|
||||
· ╰─── bool is a primitive type and does not have any fields
|
||||
───╯
|
2
integration/fail/no-such-field/assignment-bool-field.txt
Normal file
2
integration/fail/no-such-field/assignment-bool-field.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
let foo: bool = true;
|
||||
foo.bar = true;
|
7
integration/fail/no-such-field/assignment-bool-index.out
Normal file
7
integration/fail/no-such-field/assignment-bool-index.out
Normal file
|
@ -0,0 +1,7 @@
|
|||
Error: No such field
|
||||
╭─[assignment-bool-index.txt:2:5]
|
||||
│
|
||||
2 │ foo.0 = true;
|
||||
· ┬
|
||||
· ╰── bool is a primitive type and does not have any fields
|
||||
───╯
|
2
integration/fail/no-such-field/assignment-bool-index.txt
Normal file
2
integration/fail/no-such-field/assignment-bool-index.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
let foo: bool = true;
|
||||
foo.0 = true;
|
7
integration/fail/no-such-field/assignment-int-field.out
Normal file
7
integration/fail/no-such-field/assignment-int-field.out
Normal file
|
@ -0,0 +1,7 @@
|
|||
Error: No such field
|
||||
╭─[assignment-int-field.txt:2:5]
|
||||
│
|
||||
2 │ foo.bar = 1;
|
||||
· ─┬─
|
||||
· ╰─── int is a primitive type and does not have any fields
|
||||
───╯
|
2
integration/fail/no-such-field/assignment-int-field.txt
Normal file
2
integration/fail/no-such-field/assignment-int-field.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
let foo: int = 1;
|
||||
foo.bar = 1;
|
7
integration/fail/no-such-field/assignment-int-index.out
Normal file
7
integration/fail/no-such-field/assignment-int-index.out
Normal file
|
@ -0,0 +1,7 @@
|
|||
Error: No such field
|
||||
╭─[assignment-int-index.txt:2:5]
|
||||
│
|
||||
2 │ foo.0 = 1;
|
||||
· ┬
|
||||
· ╰── int is a primitive type and does not have any fields
|
||||
───╯
|
2
integration/fail/no-such-field/assignment-int-index.txt
Normal file
2
integration/fail/no-such-field/assignment-int-index.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
let foo: int = 1;
|
||||
foo.0 = 1;
|
|
@ -0,0 +1,9 @@
|
|||
Error: No such field
|
||||
╭─[assignment-tuple-field.txt:2:5]
|
||||
│
|
||||
2 │ foo.first = 0;
|
||||
· ──┬──
|
||||
· ╰──── tuples don't have named fields
|
||||
·
|
||||
· Help: To access the first element in a tuple, use `.0`
|
||||
───╯
|
|
@ -0,0 +1,2 @@
|
|||
let foo: (int,) = (1,);
|
||||
foo.first = 0;
|
|
@ -0,0 +1,9 @@
|
|||
Error: No such field
|
||||
╭─[assignment-tuple-out-of-bounds.txt:2:5]
|
||||
│
|
||||
2 │ foo.2 = 0;
|
||||
· ┬
|
||||
· ╰── this tuple does not have enough elements
|
||||
·
|
||||
· Note: The first element in a tuple has index 0
|
||||
───╯
|
|
@ -0,0 +1,2 @@
|
|||
let foo: (int,) = (1,);
|
||||
foo.2 = 0;
|
|
@ -0,0 +1,11 @@
|
|||
Error: Too few arguments
|
||||
╭─[expected-2-found-1-generic.txt:4:17]
|
||||
│
|
||||
2 │ fn foo<V>(foo: V, bar: V) {}
|
||||
· ─┬─
|
||||
· ╰─── This function takes 2 arguments,
|
||||
·
|
||||
4 │ let _unit: () = foo::<int>(1);
|
||||
· ─┬─
|
||||
· ╰─── but only 1 arguments were supplied
|
||||
───╯
|
|
@ -0,0 +1,4 @@
|
|||
// This function does nothing.
|
||||
fn foo<V>(foo: V, bar: V) {}
|
||||
|
||||
let _unit: () = foo::<int>(1);
|
11
integration/fail/too-xxx-arguments/expected-2-found-1.out
Normal file
11
integration/fail/too-xxx-arguments/expected-2-found-1.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
Error: Too few arguments
|
||||
╭─[expected-2-found-1.txt:4:17]
|
||||
│
|
||||
2 │ fn foo(foo: int, bar: int) {}
|
||||
· ─┬─
|
||||
· ╰─── This function takes 2 arguments,
|
||||
·
|
||||
4 │ let _unit: () = foo(1);
|
||||
· ─┬─
|
||||
· ╰─── but only 1 arguments were supplied
|
||||
───╯
|
|
@ -0,0 +1,4 @@
|
|||
// This function does nothing.
|
||||
fn foo(foo: int, bar: int) {}
|
||||
|
||||
let _unit: () = foo(1);
|
10
integration/fail/type-mismatch/assignment-bool-int.out
Normal file
10
integration/fail/type-mismatch/assignment-bool-int.out
Normal file
|
@ -0,0 +1,10 @@
|
|||
Error: Type Mismatch
|
||||
╭─[assignment-bool-int.txt:2:7]
|
||||
│
|
||||
1 │ let foo: bool = true;
|
||||
· ──┬─
|
||||
· ╰─── Expected type `bool`,
|
||||
2 │ foo = 0;
|
||||
· ┬
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
2
integration/fail/type-mismatch/assignment-bool-int.txt
Normal file
2
integration/fail/type-mismatch/assignment-bool-int.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
let foo: bool = true;
|
||||
foo = 0;
|
|
@ -0,0 +1,10 @@
|
|||
Error: Type Mismatch
|
||||
╭─[assignment-rc-tuple-bool-int.txt:2:9]
|
||||
│
|
||||
1 │ let foo: Rc<(bool,)> = Rc((true,));
|
||||
· ──┬─
|
||||
· ╰─── Expected type `bool`,
|
||||
2 │ foo.0 = 0;
|
||||
· ┬
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
|
@ -0,0 +1,2 @@
|
|||
let foo: Rc<(bool,)> = Rc((true,));
|
||||
foo.0 = 0;
|
|
@ -0,0 +1,10 @@
|
|||
Error: Type Mismatch
|
||||
╭─[assignment-rc-tuple-option-rc.txt:2:9]
|
||||
│
|
||||
1 │ let foo: Rc<(Option<bool>,)> = Rc((None,));
|
||||
· ───┬──
|
||||
· ╰──── Expected type `Option<bool>`,
|
||||
2 │ foo.0 = Rc(true);
|
||||
· ─┬
|
||||
· ╰── but expression is of type `Rc<_>`
|
||||
───╯
|
|
@ -0,0 +1,2 @@
|
|||
let foo: Rc<(Option<bool>,)> = Rc((None,));
|
||||
foo.0 = Rc(true);
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-bool-int-arithmetic.txt:1:17]
|
||||
│
|
||||
1 │ let foo: bool = 1 + 2;
|
||||
· ──┬─ ──┬──
|
||||
· ╰─────────── Expected type `bool`,
|
||||
· │
|
||||
· ╰──── but expression is of type `int`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: bool = 1 + 2;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-bool-int-negation.txt:2:17]
|
||||
│
|
||||
2 │ let foo: bool = -one;
|
||||
· ──┬─ ┬
|
||||
· ╰─────── Expected type `bool`,
|
||||
· │
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
|
@ -0,0 +1,2 @@
|
|||
let one: int = 1;
|
||||
let foo: bool = -one;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-bool-int-tuple-bool-bool-tuple.txt:1:31]
|
||||
│
|
||||
1 │ let foo: (bool, int) = (true, true);
|
||||
· ─┬─ ──┬─
|
||||
· ╰────────────────── Expected type `int`,
|
||||
· │
|
||||
· ╰─── but expression is of type `bool`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: (bool, int) = (true, true);
|
9
integration/fail/type-mismatch/declaration-bool-int.out
Normal file
9
integration/fail/type-mismatch/declaration-bool-int.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-bool-int.txt:1:17]
|
||||
│
|
||||
1 │ let foo: bool = 0;
|
||||
· ──┬─ ┬
|
||||
· ╰─────── Expected type `bool`,
|
||||
· │
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
1
integration/fail/type-mismatch/declaration-bool-int.txt
Normal file
1
integration/fail/type-mismatch/declaration-bool-int.txt
Normal file
|
@ -0,0 +1 @@
|
|||
let foo: bool = 0;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-int-bool-conjunction.txt:1:16]
|
||||
│
|
||||
1 │ let foo: int = true && true;
|
||||
· ─┬─ ──────┬─────
|
||||
· ╰────────────────── Expected type `int`,
|
||||
· │
|
||||
· ╰─────── but expression is of type `bool`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: int = true && true;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-int-bool-negation.txt:2:16]
|
||||
│
|
||||
2 │ let foo: int = !yes;
|
||||
· ─┬─ ┬
|
||||
· ╰─────── Expected type `int`,
|
||||
· │
|
||||
· ╰── but expression is of type `bool`
|
||||
───╯
|
|
@ -0,0 +1,2 @@
|
|||
let yes: bool = true;
|
||||
let foo: int = !yes;
|
9
integration/fail/type-mismatch/declaration-int-bool.out
Normal file
9
integration/fail/type-mismatch/declaration-int-bool.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-int-bool.txt:1:16]
|
||||
│
|
||||
1 │ let foo: int = true;
|
||||
· ─┬─ ──┬─
|
||||
· ╰────────── Expected type `int`,
|
||||
· │
|
||||
· ╰─── but expression is of type `bool`
|
||||
───╯
|
1
integration/fail/type-mismatch/declaration-int-bool.txt
Normal file
1
integration/fail/type-mismatch/declaration-int-bool.txt
Normal file
|
@ -0,0 +1 @@
|
|||
let foo: int = true;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-int-int-comparison.txt:1:16]
|
||||
│
|
||||
1 │ let foo: int = 1 == 2;
|
||||
· ─┬─ ───┬──
|
||||
· ╰──────────── Expected type `int`,
|
||||
· │
|
||||
· ╰──── but expression is of type `bool`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: int = 1 == 2;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-int-tuple-bool-tuple.txt:1:20]
|
||||
│
|
||||
1 │ let foo: (int,) = (true,);
|
||||
· ─┬─ ──┬─
|
||||
· ╰───────────── Expected type `int`,
|
||||
· │
|
||||
· ╰─── but expression is of type `bool`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: (int,) = (true,);
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[declaration-unit-one-tuple.txt:1:15]
|
||||
│
|
||||
1 │ let foo: () = (1,);
|
||||
· ─┬ ──┬─
|
||||
· ╰───────── Expected tuple with 0 elements,
|
||||
· │
|
||||
· ╰─── but expression has 1 elements
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: () = (1,);
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[expression-arithmetic-int-bool.txt:1:20]
|
||||
│
|
||||
1 │ let foo: int = 1 + true;
|
||||
· ┬ ──┬─
|
||||
· ╰─────── Expected type `int`,
|
||||
· │
|
||||
· ╰─── but expression is of type `bool`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: int = 1 + true;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[expression-comparison-int-bool.txt:1:22]
|
||||
│
|
||||
1 │ let foo: bool = 1 == true;
|
||||
· ─┬ ──┬─
|
||||
· ╰─────── Expected type `int`,
|
||||
· │
|
||||
· ╰─── but expression is of type `bool`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: bool = 1 == true;
|
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[expression-conjunction-bool-int.txt:1:25]
|
||||
│
|
||||
1 │ let foo: bool = true || 1;
|
||||
· ─┬ ┬
|
||||
· ╰──── Expected type `bool`,
|
||||
· │
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
|
@ -0,0 +1 @@
|
|||
let foo: bool = true || 1;
|
9
integration/fail/type-mismatch/expression-int-0.out
Normal file
9
integration/fail/type-mismatch/expression-int-0.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[expression-int-0.txt:2:16]
|
||||
│
|
||||
2 │ let bar: int = foo.0;
|
||||
· ──┬─┬
|
||||
· ╰──── Expression is of type `int`,
|
||||
· │
|
||||
· ╰── but expected type `(_, ..)`
|
||||
───╯
|
2
integration/fail/type-mismatch/expression-int-0.txt
Normal file
2
integration/fail/type-mismatch/expression-int-0.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
let foo: int = 1;
|
||||
let bar: int = foo.0;
|
9
integration/fail/type-mismatch/expression-minus-bool.out
Normal file
9
integration/fail/type-mismatch/expression-minus-bool.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[expression-minus-bool.txt:1:17]
|
||||
│
|
||||
1 │ let foo: int = -true;
|
||||
· ┬──┬─
|
||||
· ╰────── Expected type `int`,
|
||||
· │
|
||||
· ╰─── but expression is of type `bool`
|
||||
───╯
|
1
integration/fail/type-mismatch/expression-minus-bool.txt
Normal file
1
integration/fail/type-mismatch/expression-minus-bool.txt
Normal file
|
@ -0,0 +1 @@
|
|||
let foo: int = -true;
|
9
integration/fail/type-mismatch/expression-not-int.out
Normal file
9
integration/fail/type-mismatch/expression-not-int.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[expression-not-int.txt:1:18]
|
||||
│
|
||||
1 │ let foo: bool = !0;
|
||||
· ┬┬
|
||||
· ╰─── Expected type `bool`,
|
||||
· │
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
1
integration/fail/type-mismatch/expression-not-int.txt
Normal file
1
integration/fail/type-mismatch/expression-not-int.txt
Normal file
|
@ -0,0 +1 @@
|
|||
let foo: bool = !0;
|
9
integration/fail/type-mismatch/expression-unit-0.out
Normal file
9
integration/fail/type-mismatch/expression-unit-0.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[expression-unit-0.txt:1:16]
|
||||
│
|
||||
1 │ let foo: int = ().0;
|
||||
· ─┬┬─
|
||||
· ╰──── Found tuple with 0 elements,
|
||||
· │
|
||||
· ╰─── but expression requires at least 1 elements
|
||||
───╯
|
1
integration/fail/type-mismatch/expression-unit-0.txt
Normal file
1
integration/fail/type-mismatch/expression-unit-0.txt
Normal file
|
@ -0,0 +1 @@
|
|||
let foo: int = ().0;
|
9
integration/fail/type-mismatch/if-condition-int.out
Normal file
9
integration/fail/type-mismatch/if-condition-int.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[if-condition-int.txt:1:4]
|
||||
│
|
||||
1 │ if 0 {}
|
||||
· ─┬ ┬
|
||||
· ╰──── Expected type `bool`,
|
||||
· │
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
1
integration/fail/type-mismatch/if-condition-int.txt
Normal file
1
integration/fail/type-mismatch/if-condition-int.txt
Normal file
|
@ -0,0 +1 @@
|
|||
if 0 {}
|
9
integration/fail/type-mismatch/while-condition-int.out
Normal file
9
integration/fail/type-mismatch/while-condition-int.out
Normal file
|
@ -0,0 +1,9 @@
|
|||
Error: Type Mismatch
|
||||
╭─[while-condition-int.txt:1:7]
|
||||
│
|
||||
1 │ while 0 {}
|
||||
· ──┬── ┬
|
||||
· ╰────── Expected type `bool`,
|
||||
· │
|
||||
· ╰── but expression is of type `int`
|
||||
───╯
|
1
integration/fail/type-mismatch/while-condition-int.txt
Normal file
1
integration/fail/type-mismatch/while-condition-int.txt
Normal file
|
@ -0,0 +1 @@
|
|||
while 0 {}
|
7
integration/fail/unknown-type/declaration.out
Normal file
7
integration/fail/unknown-type/declaration.out
Normal file
|
@ -0,0 +1,7 @@
|
|||
Error: Unknown type
|
||||
╭─[declaration.txt:1:10]
|
||||
│
|
||||
1 │ let foo: Foo = 0;
|
||||
· ─┬─
|
||||
· ╰─── This type has not been defined
|
||||
───╯
|
1
integration/fail/unknown-type/declaration.txt
Normal file
1
integration/fail/unknown-type/declaration.txt
Normal file
|
@ -0,0 +1 @@
|
|||
let foo: Foo = 0;
|
116
integration/main.rs
Normal file
116
integration/main.rs
Normal file
|
@ -0,0 +1,116 @@
|
|||
#![warn(rust_2018_idioms)]
|
||||
#![deny(elided_lifetimes_in_paths)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use compiler::{
|
||||
compile::{compile, CompileResult},
|
||||
diagnostic::{Diagnostic, Source}
|
||||
};
|
||||
use lazy_regex::regex_replace_all;
|
||||
use libtest::{run_tests, Arguments, Outcome, Test};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::{Read as _, Write as _},
|
||||
panic::catch_unwind,
|
||||
path::{Path, PathBuf}
|
||||
};
|
||||
|
||||
struct TestData {
|
||||
path: PathBuf
|
||||
}
|
||||
|
||||
fn run_test(data: &TestData) -> anyhow::Result<()> {
|
||||
let mut file = File::open(&data.path)?;
|
||||
let mut input = String::new();
|
||||
file.read_to_string(&mut input)?;
|
||||
drop(file);
|
||||
|
||||
let compile_result = match catch_unwind(|| compile(&input)) {
|
||||
Ok(result) => result,
|
||||
Err(e) => match e.downcast_ref::<String>() {
|
||||
Some(str) => anyhow::bail!("The compiler paniced: {str}"),
|
||||
None => match e.downcast_ref::<&str>() {
|
||||
Some(str) => anyhow::bail!("The compiler paniced: {str}"),
|
||||
None => anyhow::bail!("The compiler paniced")
|
||||
}
|
||||
}
|
||||
};
|
||||
let msg = match compile_result {
|
||||
Ok(CompileResult::Ok { .. }) => anyhow::bail!("Code compiled successfully"),
|
||||
Ok(CompileResult::InternalErr(code, err)) => {
|
||||
let mut buf = Vec::new();
|
||||
Diagnostic::ice(err).write(Source::new(&code), &mut buf)?;
|
||||
String::from_utf8(buf).unwrap()
|
||||
},
|
||||
Err(err) => {
|
||||
let filename = data.path.file_name().unwrap().to_str().unwrap();
|
||||
let mut buf = Vec::new();
|
||||
err.write(Source::new(&input).with_filename(filename), &mut buf)?;
|
||||
String::from_utf8(buf).unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
// remove colors from the msg
|
||||
let msg = regex_replace_all!("\x1B\\[[^m]+m", &msg, |_| "");
|
||||
|
||||
let mut path = data.path.clone();
|
||||
path.set_extension("out");
|
||||
if !path.exists() {
|
||||
let mut file = File::create(&path)?;
|
||||
write!(file, "{msg}")?;
|
||||
Ok(())
|
||||
} else {
|
||||
let mut file = File::open(&path)?;
|
||||
let mut buf = String::new();
|
||||
file.read_to_string(&mut buf)?;
|
||||
drop(file);
|
||||
|
||||
if msg == buf {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow::anyhow!(
|
||||
"Error: Expected output\n\n{buf}\n\nActual output\n\n{msg}"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_tests_from_dir<P>(tests: &mut Vec<Test<TestData>>, path: P) -> anyhow::Result<()>
|
||||
where
|
||||
P: AsRef<Path>
|
||||
{
|
||||
for file in fs::read_dir(path)? {
|
||||
let file = file?;
|
||||
let path = file.path();
|
||||
let ty = file.file_type()?;
|
||||
if ty.is_dir() {
|
||||
add_tests_from_dir(tests, &path)?;
|
||||
} else if ty.is_file()
|
||||
&& path.extension().map(|ext| ext == "txt").unwrap_or(false)
|
||||
{
|
||||
tests.push(Test {
|
||||
name: path.display().to_string(),
|
||||
kind: "".into(),
|
||||
is_ignored: false,
|
||||
is_bench: false,
|
||||
data: TestData { path }
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let args = Arguments::from_args();
|
||||
|
||||
let mut tests = Vec::new();
|
||||
add_tests_from_dir(&mut tests, "integration/fail")?;
|
||||
|
||||
run_tests(&args, tests, |test| match run_test(&test.data) {
|
||||
Ok(()) => Outcome::Passed,
|
||||
Err(err) => Outcome::Failed {
|
||||
msg: Some(format!("{err:?}"))
|
||||
}
|
||||
})
|
||||
.exit();
|
||||
}
|
Reference in a new issue