std
This commit is contained in:
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
A very cool language
|
A very cool language
|
||||||
|
|
||||||
|
## Huh?
|
||||||
|
* Indentation-based syntax
|
||||||
|
* Compiled to x86_64 Assembly
|
||||||
|
* Sometimes works
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
```go
|
```go
|
||||||
func fib[n: I64] : I64
|
func fib[n: I64] : I64
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let sum: I64 = 0
|
let sum: I64 = 0
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,9 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func is_prime[n: I64]: I64
|
|
||||||
if n <= 1
|
|
||||||
return false
|
|
||||||
if n == 2 || n == 3
|
|
||||||
return true
|
|
||||||
if n % 2 == 0 || n % 3 == 0
|
|
||||||
return false
|
|
||||||
|
|
||||||
let i: I64 = 5
|
|
||||||
while i * i <= n
|
|
||||||
if n % i == 0 || n % (i + 2) == 0
|
|
||||||
return false
|
|
||||||
i = i + 6
|
|
||||||
return true
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let sum: I64 = 0
|
let sum: I64 = 0
|
||||||
|
|
||||||
let i: I64 = 0
|
let i: I64 = 0
|
||||||
while i < 2000000
|
while i < 2000000
|
||||||
if is_prime(i)
|
if Math.is_prime(i)
|
||||||
sum = sum + i
|
sum = sum + i
|
||||||
i = i + 1
|
i = i + 1
|
||||||
print_i64(sum)
|
print_i64(sum)
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func num_divisors[n: I64] : I64
|
func num_divisors[n: I64] : I64
|
||||||
let end: I64 = isqrt(n)
|
let end: I64 = isqrt(n)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func collatz_num[n: I64] : I64
|
func collatz_num[n: I64] : I64
|
||||||
if n % 2 == 0
|
if n % 2 == 0
|
||||||
return n / 2
|
return n / 2
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let sum: I64 = 0
|
let sum: I64 = 0
|
||||||
let a: I64 = 0
|
let a: I64 = 0
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let n: I64 = 600851475143
|
let n: I64 = 600851475143
|
||||||
let f: I64 = 2
|
let f: I64 = 2
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func I64.to_string[n: I64] : String
|
|
||||||
let x: I64 = malloc(21)
|
|
||||||
sprintf(x, "%ld", n)
|
|
||||||
return x
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let out: I64 = 0
|
let out: I64 = 0
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,8 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func gcd[a: I64, b: I64] : I64
|
|
||||||
while b != 0
|
|
||||||
let tmp: I64 = b
|
|
||||||
b = a % b
|
|
||||||
a = tmp
|
|
||||||
return a
|
|
||||||
|
|
||||||
func lcm[a: I64, b: I64] : I64
|
|
||||||
return (a * b) / gcd(a, b)
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let out: I64 = 1
|
let out: I64 = 1
|
||||||
|
|
||||||
let i: I64 = 1
|
let i: I64 = 1
|
||||||
while i < 21
|
while i < 21
|
||||||
out = lcm(out, i)
|
out = Math.lcm(out, i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
print_i64(out)
|
print_i64(out)
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let sum_of_squares: I64 = 0
|
let sum_of_squares: I64 = 0
|
||||||
let i: I64 = 1
|
let i: I64 = 1
|
||||||
|
|||||||
@@ -1,27 +1,9 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func is_prime[n: I64]: I64
|
|
||||||
if n <= 1
|
|
||||||
return false
|
|
||||||
if n == 2 || n == 3
|
|
||||||
return true
|
|
||||||
if n % 2 == 0 || n % 3 == 0
|
|
||||||
return false
|
|
||||||
|
|
||||||
let i: I64 = 5
|
|
||||||
while i * i <= n
|
|
||||||
if n % i == 0 || n % (i + 2) == 0
|
|
||||||
return false
|
|
||||||
i = i + 6
|
|
||||||
return true
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let found: I64 = 0
|
let found: I64 = 0
|
||||||
|
|
||||||
let i: I64 = 1
|
let i: I64 = 1
|
||||||
while 1
|
while 1
|
||||||
if is_prime(i)
|
if Math.is_prime(i)
|
||||||
found = found + 1
|
found = found + 1
|
||||||
if found == 10001
|
if found == 10001
|
||||||
print_i64(i)
|
print_i64(i)
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func char_to_i64[c: I64]: I64
|
|
||||||
return c - 48
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let n: String = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450"
|
let n: String = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450"
|
||||||
|
|
||||||
@@ -14,7 +8,7 @@ func main[] : I64
|
|||||||
let s: I64 = 1
|
let s: I64 = 1
|
||||||
let j: I64 = 0
|
let j: I64 = 0
|
||||||
while j < 13
|
while j < 13
|
||||||
s = s * char_to_i64(nth(n, i + j))
|
s = s * Char.to_i64(nth(n, i + j))
|
||||||
j = j + 1
|
j = j + 1
|
||||||
if s > out
|
if s > out
|
||||||
out = s
|
out = s
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let a: I64 = 1
|
let a: I64 = 1
|
||||||
while a < 1000
|
while a < 1000
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let a: I64 = 0
|
let a: I64 = 0
|
||||||
let b: I64 = 1
|
let b: I64 = 1
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
func print_i64[x: I64] : I64
|
|
||||||
printf("%ld\n", x)
|
|
||||||
|
|
||||||
func I64.to_string[n: I64] : String
|
|
||||||
let x: String = malloc(21)
|
|
||||||
sprintf(x, "%ld", n)
|
|
||||||
return x
|
|
||||||
|
|
||||||
func main[] : I64
|
func main[] : I64
|
||||||
let s: String = I64.to_string(58394)
|
let a: String = I64.to_string(58394)
|
||||||
print_i64(strlen(s))
|
print_i64(strlen(a))
|
||||||
free(s)
|
let b: String = concat(a, "test")
|
||||||
|
print_i64(strlen(b))
|
||||||
|
free(a)
|
||||||
|
free(b)
|
||||||
@@ -101,11 +101,14 @@ extern printf
|
|||||||
extern sprintf
|
extern sprintf
|
||||||
extern strlen
|
extern strlen
|
||||||
extern strcmp
|
extern strcmp
|
||||||
|
extern strcat
|
||||||
|
extern strcpy
|
||||||
|
extern strdup
|
||||||
extern puts
|
extern puts
|
||||||
extern system
|
extern system
|
||||||
print equ puts
|
extern exit
|
||||||
|
copystr equ strdup
|
||||||
|
|
||||||
; generated with clang
|
|
||||||
strrev:
|
strrev:
|
||||||
push r14
|
push r14
|
||||||
push rbx
|
push rbx
|
||||||
@@ -118,15 +121,15 @@ strrev:
|
|||||||
mov rcx, rax
|
mov rcx, rax
|
||||||
mov rsi, r14
|
mov rsi, r14
|
||||||
mov rdx, r14
|
mov rdx, r14
|
||||||
.LBB0_1:
|
.strrev.1:
|
||||||
sub rdx, 1
|
sub rdx, 1
|
||||||
jb .LBB0_2
|
jb .strrev.2
|
||||||
mov sil, byte [rbx + rsi - 1]
|
mov sil, byte [rbx + rsi - 1]
|
||||||
mov byte [rcx], sil
|
mov byte [rcx], sil
|
||||||
inc rcx
|
inc rcx
|
||||||
mov rsi, rdx
|
mov rsi, rdx
|
||||||
jmp .LBB0_1
|
jmp .strrev.1
|
||||||
.LBB0_2:
|
.strrev.2:
|
||||||
mov byte [rax + r14], 0
|
mov byte [rax + r14], 0
|
||||||
add rsp, 8
|
add rsp, 8
|
||||||
pop rbx
|
pop rbx
|
||||||
@@ -138,30 +141,30 @@ isqrt:
|
|||||||
mov rcx, 1
|
mov rcx, 1
|
||||||
mov rbx, rdi
|
mov rbx, rdi
|
||||||
shl rcx, 62
|
shl rcx, 62
|
||||||
.LBB0_3:
|
.isqrt.1:
|
||||||
cmp rcx, 0
|
cmp rcx, 0
|
||||||
je .LBB0_5
|
je .isqrt.5
|
||||||
cmp rcx, rbx
|
cmp rcx, rbx
|
||||||
jbe .LBB0_4
|
jbe .isqrt.2
|
||||||
shr rcx, 2
|
shr rcx, 2
|
||||||
jmp .LBB0_3
|
jmp .isqrt.1
|
||||||
.LBB0_4:
|
.isqrt.2:
|
||||||
cmp rcx, 0
|
cmp rcx, 0
|
||||||
je .LBB0_5
|
je .isqrt.5
|
||||||
mov rdx, rax
|
mov rdx, rax
|
||||||
add rdx, rcx
|
add rdx, rcx
|
||||||
cmp rbx, rdx
|
cmp rbx, rdx
|
||||||
jb .LBB0_7
|
jb .isqrt.3
|
||||||
sub rbx, rdx
|
sub rbx, rdx
|
||||||
shr rax, 1
|
shr rax, 1
|
||||||
add rax, rcx
|
add rax, rcx
|
||||||
jmp .LBB0_6
|
jmp .isqrt.4
|
||||||
.LBB0_7:
|
.isqrt.3:
|
||||||
shr rax, 1
|
shr rax, 1
|
||||||
.LBB0_6:
|
.isqrt.4:
|
||||||
shr rcx, 2
|
shr rcx, 2
|
||||||
jmp .LBB0_4
|
jmp .isqrt.2
|
||||||
.LBB0_5:
|
.isqrt.5:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
nth:
|
nth:
|
||||||
@@ -259,10 +262,8 @@ nth:
|
|||||||
|
|
||||||
self.compile_stmt(env, *body)?;
|
self.compile_stmt(env, *body)?;
|
||||||
|
|
||||||
if name.lexeme == "main" {
|
// TODO: default exit code only for main
|
||||||
// default exit code
|
|
||||||
emit!(&mut self.output, " mov rax, 0");
|
emit!(&mut self.output, " mov rax, 0");
|
||||||
}
|
|
||||||
|
|
||||||
emit!(&mut self.output, " mov rsp, rbp");
|
emit!(&mut self.output, " mov rsp, rbp");
|
||||||
emit!(&mut self.output, " pop rbp");
|
emit!(&mut self.output, " pop rbp");
|
||||||
@@ -356,6 +357,10 @@ nth:
|
|||||||
TokenType::String => {
|
TokenType::String => {
|
||||||
// TODO: actual string parsing in the tokenizer
|
// TODO: actual string parsing in the tokenizer
|
||||||
let value = &token.lexeme[1..token.lexeme.len() - 1].replace("\\n", "\n");
|
let value = &token.lexeme[1..token.lexeme.len() - 1].replace("\\n", "\n");
|
||||||
|
|
||||||
|
if value.is_empty() {
|
||||||
|
emit!(&mut self.data_section, " S{} db 0", self.data_counter);
|
||||||
|
} else {
|
||||||
let charcodes = value
|
let charcodes = value
|
||||||
.chars()
|
.chars()
|
||||||
.map(|x| (x as u8).to_string())
|
.map(|x| (x as u8).to_string())
|
||||||
@@ -367,6 +372,7 @@ nth:
|
|||||||
self.data_counter,
|
self.data_counter,
|
||||||
charcodes,
|
charcodes,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
emit!(&mut self.output, " mov rax, S{}", self.data_counter);
|
emit!(&mut self.output, " mov rax, S{}", self.data_counter);
|
||||||
self.data_counter += 1;
|
self.data_counter += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/main.rs
29
src/main.rs
@@ -10,6 +10,23 @@ use std::{
|
|||||||
|
|
||||||
use tokenizer::ZernError;
|
use tokenizer::ZernError;
|
||||||
|
|
||||||
|
fn compile_file_to(
|
||||||
|
codegen: &mut codegen_x86_64::CodegenX86_64,
|
||||||
|
filename: &str,
|
||||||
|
source: String,
|
||||||
|
) -> Result<(), ZernError> {
|
||||||
|
let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
|
||||||
|
let tokens = tokenizer.tokenize()?;
|
||||||
|
|
||||||
|
let parser = parser::Parser::new(tokens);
|
||||||
|
let statements = parser.parse()?;
|
||||||
|
|
||||||
|
for stmt in statements {
|
||||||
|
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_file(path: String) -> Result<(), ZernError> {
|
fn compile_file(path: String) -> Result<(), ZernError> {
|
||||||
let source = match fs::read_to_string(path.clone()) {
|
let source = match fs::read_to_string(path.clone()) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
@@ -21,18 +38,10 @@ fn compile_file(path: String) -> Result<(), ZernError> {
|
|||||||
|
|
||||||
let filename = Path::new(&path).file_name().unwrap().to_str().unwrap();
|
let filename = Path::new(&path).file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
|
|
||||||
let tokens = tokenizer.tokenize()?;
|
|
||||||
|
|
||||||
let parser = parser::Parser::new(tokens);
|
|
||||||
let statements = parser.parse()?;
|
|
||||||
|
|
||||||
let mut codegen = codegen_x86_64::CodegenX86_64::new();
|
let mut codegen = codegen_x86_64::CodegenX86_64::new();
|
||||||
|
|
||||||
codegen.emit_prologue()?;
|
codegen.emit_prologue()?;
|
||||||
for stmt in statements {
|
compile_file_to(&mut codegen, "std.zr", include_str!("std.zr").into())?;
|
||||||
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?;
|
compile_file_to(&mut codegen, filename, source)?;
|
||||||
}
|
|
||||||
codegen.emit_epilogue()?;
|
codegen.emit_epilogue()?;
|
||||||
|
|
||||||
if fs::write("out.s", codegen.get_output()).is_err() {
|
if fs::write("out.s", codegen.get_output()).is_err() {
|
||||||
|
|||||||
67
src/std.zr
Normal file
67
src/std.zr
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
func print[x: String] : I64
|
||||||
|
printf("%s\n", x)
|
||||||
|
|
||||||
|
func print_i64[x: I64] : I64
|
||||||
|
printf("%ld\n", x)
|
||||||
|
|
||||||
|
func concat[a: String, b: String] : String
|
||||||
|
let c: String = malloc(strlen(a) + strlen(b) + 1)
|
||||||
|
strcpy(c, a)
|
||||||
|
strcat(c, b)
|
||||||
|
return c
|
||||||
|
|
||||||
|
func Char.to_i64[c: I64]: I64
|
||||||
|
return c - 48
|
||||||
|
|
||||||
|
func I64.to_string[n: I64] : String
|
||||||
|
let x: I64 = malloc(21)
|
||||||
|
sprintf(x, "%ld", n)
|
||||||
|
return x
|
||||||
|
|
||||||
|
func Math.gcd[a: I64, b: I64] : I64
|
||||||
|
while b != 0
|
||||||
|
let tmp: I64 = b
|
||||||
|
b = a % b
|
||||||
|
a = tmp
|
||||||
|
return a
|
||||||
|
|
||||||
|
func Math.min[a: I64, b: I64] : I64
|
||||||
|
if a < b
|
||||||
|
return a
|
||||||
|
return b
|
||||||
|
|
||||||
|
func Math.max[a: I64, b: I64] : I64
|
||||||
|
if a > b
|
||||||
|
return a
|
||||||
|
return b
|
||||||
|
|
||||||
|
func Math.abs[n: I64] : I64
|
||||||
|
if n < 0
|
||||||
|
return -n
|
||||||
|
return n
|
||||||
|
|
||||||
|
func Math.pow[b: I64, e: I64] : I64
|
||||||
|
let out: I64 = 1
|
||||||
|
let i: I64 = 0
|
||||||
|
while i < e
|
||||||
|
out = out * b
|
||||||
|
i = i + 1
|
||||||
|
return out
|
||||||
|
|
||||||
|
func Math.lcm[a: I64, b: I64] : I64
|
||||||
|
return (a * b) / Math.gcd(a, b)
|
||||||
|
|
||||||
|
func Math.is_prime[n: I64]: I64
|
||||||
|
if n <= 1
|
||||||
|
return false
|
||||||
|
if n == 2 || n == 3
|
||||||
|
return true
|
||||||
|
if n % 2 == 0 || n % 3 == 0
|
||||||
|
return false
|
||||||
|
|
||||||
|
let i: I64 = 5
|
||||||
|
while i * i <= n
|
||||||
|
if n % i == 0 || n % (i + 2) == 0
|
||||||
|
return false
|
||||||
|
i = i + 6
|
||||||
|
return true
|
||||||
@@ -220,7 +220,7 @@ impl Tokenizer {
|
|||||||
self.handle_indentation()?;
|
self.handle_indentation()?;
|
||||||
}
|
}
|
||||||
'0'..='9' => self.scan_number(),
|
'0'..='9' => self.scan_number(),
|
||||||
'A'..='Z' | 'a'..='z' | '_' => self.scan_identifier(),
|
'A'..='Z' | 'a'..='z' | '_' | '.' => self.scan_identifier(),
|
||||||
_ => return error!(self.loc, "unexpected character"),
|
_ => return error!(self.loc, "unexpected character"),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -295,7 +295,11 @@ impl Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn scan_identifier(&mut self) {
|
fn scan_identifier(&mut self) {
|
||||||
while self.peek().is_alphanumeric() || self.peek() == '_' || self.peek() == '.' {
|
while self.peek().is_alphanumeric()
|
||||||
|
|| self.peek() == '_'
|
||||||
|
|| self.peek() == '.'
|
||||||
|
|| self.peek() == '!'
|
||||||
|
{
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
test.py
Normal file
21
test.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
os.system("cargo build --release")
|
||||||
|
|
||||||
|
for x in os.listdir("examples/"):
|
||||||
|
print(
|
||||||
|
"\033[93mBuilding %s...\033[0m" % x,
|
||||||
|
end="",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
t = time.time()
|
||||||
|
if os.system("./target/release/zern examples/" + x) != 0:
|
||||||
|
sys.exit(1)
|
||||||
|
print(" %sms" % round((time.time() - t) * 1000, 2))
|
||||||
|
|
||||||
|
t = time.time()
|
||||||
|
if os.system("./out") != 0:
|
||||||
|
sys.exit(1)
|
||||||
|
print("\033[93mRunning %s...\033[0m %sms" % (x, round((time.time() - t) * 1000, 2)))
|
||||||
Reference in New Issue
Block a user