vh fixes for the UI module
parent
5be8b47e1c
commit
128d37c671
|
@ -17,7 +17,7 @@ pub:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private function, used by V (`nums := []int`)
|
// Private function, used by V (`nums := []int`)
|
||||||
fn new_array(mylen, cap, elm_size int) array {
|
pub fn new_array(mylen, cap, elm_size int) array {
|
||||||
arr := array {
|
arr := array {
|
||||||
len: mylen
|
len: mylen
|
||||||
cap: cap
|
cap: cap
|
||||||
|
|
|
@ -186,7 +186,7 @@ pub fn free(ptr voidptr) {
|
||||||
C.free(ptr)
|
C.free(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn memdup(src voidptr, sz int) voidptr {
|
pub fn memdup(src voidptr, sz int) voidptr {
|
||||||
mem := malloc(sz)
|
mem := malloc(sz)
|
||||||
return C.memcpy(mem, src, sz)
|
return C.memcpy(mem, src, sz)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ NB: A V string should be/is immutable from the point of view of
|
||||||
when used with modules using C functions (for example os and so on).
|
when used with modules using C functions (for example os and so on).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import strconv
|
//import strconv
|
||||||
|
|
||||||
pub struct string {
|
pub struct string {
|
||||||
//mut:
|
//mut:
|
||||||
|
@ -84,7 +84,7 @@ pub fn tos_clone(s byteptr) string {
|
||||||
|
|
||||||
// Same as `tos`, but calculates the length. Called by `string(bytes)` casts.
|
// Same as `tos`, but calculates the length. Called by `string(bytes)` casts.
|
||||||
// Used only internally.
|
// Used only internally.
|
||||||
fn tos2(s byteptr) string {
|
pub fn tos2(s byteptr) string {
|
||||||
if s == 0 {
|
if s == 0 {
|
||||||
panic('tos2: nil string')
|
panic('tos2: nil string')
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ fn tos2(s byteptr) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tos3(s *C.char) string {
|
pub fn tos3(s *C.char) string {
|
||||||
if s == 0 {
|
if s == 0 {
|
||||||
panic('tos3: nil string')
|
panic('tos3: nil string')
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,8 @@ pub fn (s string) int() int {
|
||||||
|
|
||||||
|
|
||||||
pub fn (s string) i64() i64 {
|
pub fn (s string) i64() i64 {
|
||||||
return strconv.parse_int(s, 0, 64)
|
//return strconv.parse_int(s, 0, 64)
|
||||||
|
return C.atoll(*char(s.str))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s string) f32() f32 {
|
pub fn (s string) f32() f32 {
|
||||||
|
@ -214,11 +215,13 @@ pub fn (s string) f64() f64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s string) u32() u32 {
|
pub fn (s string) u32() u32 {
|
||||||
return strconv.parse_uint(s, 0, 32)
|
return C.atol(*char(s.str))
|
||||||
|
//return strconv.parse_uint(s, 0, 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s string) u64() u64 {
|
pub fn (s string) u64() u64 {
|
||||||
return strconv.parse_uint(s, 0, 64)
|
return C.atoll(*char(s.str))
|
||||||
|
//return strconv.parse_uint(s, 0, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==
|
// ==
|
||||||
|
|
|
@ -44,6 +44,7 @@ mut:
|
||||||
body_idx int // idx of the first body statement
|
body_idx int // idx of the first body statement
|
||||||
fn_name_token_idx int // used by error reporting
|
fn_name_token_idx int // used by error reporting
|
||||||
comptime_define string
|
comptime_define string
|
||||||
|
is_used bool // so that we can skip unused fns in resulting C code
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypeInst {
|
struct TypeInst {
|
||||||
|
@ -193,9 +194,10 @@ fn (p mut Parser) fn_decl() {
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
is_pub := p.tok == .key_pub
|
||||||
mut f := Fn{
|
mut f := Fn{
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
is_public: p.tok == .key_pub || p.is_vh // functions defined in .vh are always public
|
is_public: is_pub || p.is_vh // functions defined in .vh are always public
|
||||||
is_unsafe: p.attr == 'unsafe_fn'
|
is_unsafe: p.attr == 'unsafe_fn'
|
||||||
is_deprecated: p.attr == 'deprecated'
|
is_deprecated: p.attr == 'deprecated'
|
||||||
comptime_define: if p.attr.starts_with('if ') { p.attr.right(3) } else { '' }
|
comptime_define: if p.attr.starts_with('if ') { p.attr.right(3) } else { '' }
|
||||||
|
@ -204,12 +206,13 @@ fn (p mut Parser) fn_decl() {
|
||||||
if p.attr == 'live' && p.first_pass() && !p.pref.is_live && !p.pref.is_so {
|
if p.attr == 'live' && p.first_pass() && !p.pref.is_live && !p.pref.is_so {
|
||||||
println('INFO: run `v -live program.v` if you want to use [live] functions')
|
println('INFO: run `v -live program.v` if you want to use [live] functions')
|
||||||
}
|
}
|
||||||
if f.is_public {
|
if is_pub {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
p.returns = false
|
p.returns = false
|
||||||
//p.gen('/* returns $p.returns */')
|
//p.gen('/* returns $p.returns */')
|
||||||
p.next()
|
p.next()
|
||||||
|
|
||||||
// Method receiver
|
// Method receiver
|
||||||
mut receiver_typ := ''
|
mut receiver_typ := ''
|
||||||
if p.tok == .lpar {
|
if p.tok == .lpar {
|
||||||
|
@ -277,9 +280,9 @@ fn (p mut Parser) fn_decl() {
|
||||||
// C function header def? (fn C.NSMakeRect(int,int,int,int))
|
// C function header def? (fn C.NSMakeRect(int,int,int,int))
|
||||||
is_c := f.name == 'C' && p.tok == .dot
|
is_c := f.name == 'C' && p.tok == .dot
|
||||||
// Just fn signature? only builtin.v + default build mode
|
// Just fn signature? only builtin.v + default build mode
|
||||||
//if p.pref.is_verbose {
|
if p.is_vh {
|
||||||
//println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
|
//println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
|
||||||
//}
|
}
|
||||||
if is_c {
|
if is_c {
|
||||||
p.check(.dot)
|
p.check(.dot)
|
||||||
f.name = p.check_name()
|
f.name = p.check_name()
|
||||||
|
@ -691,6 +694,7 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
|
||||||
p.error('use `malloc()` instead of `C.malloc()`')
|
p.error('use `malloc()` instead of `C.malloc()`')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
f.is_used = true
|
||||||
cgen_name := p.table.fn_gen_name(f)
|
cgen_name := p.table.fn_gen_name(f)
|
||||||
p.next() // fn name
|
p.next() // fn name
|
||||||
if p.tok == .lt {
|
if p.tok == .lt {
|
||||||
|
|
|
@ -20,8 +20,6 @@ fn generate_vh(mod string) {
|
||||||
println('\n\n\n\nGenerating a V header file for module `$mod`')
|
println('\n\n\n\nGenerating a V header file for module `$mod`')
|
||||||
vexe := os.executable()
|
vexe := os.executable()
|
||||||
full_mod_path := os.dir(vexe) + '/' + mod
|
full_mod_path := os.dir(vexe) + '/' + mod
|
||||||
|
|
||||||
|
|
||||||
mod_path := mod.replace('.', os.path_separator)
|
mod_path := mod.replace('.', os.path_separator)
|
||||||
dir := if mod.starts_with('vlib') {
|
dir := if mod.starts_with('vlib') {
|
||||||
'$compiler.v_modules_path${os.path_separator}$mod'
|
'$compiler.v_modules_path${os.path_separator}$mod'
|
||||||
|
@ -64,9 +62,10 @@ fn generate_vh(mod string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
match tok.tok {
|
match tok.tok {
|
||||||
.key_fn { fns.writeln(generate_fn(p.tokens, i)) }
|
.key_fn { fns.writeln(generate_fn(p.tokens, i)) }
|
||||||
.key_const { consts.writeln(generate_const(p.tokens, i)) }
|
.key_const { consts.writeln(generate_const(p.tokens, i)) }
|
||||||
.key_struct { types.writeln(generate_type(p.tokens, i)) }
|
.key_struct { types.writeln(generate_type(p.tokens, i)) }
|
||||||
|
.key_type { types.writeln(generate_alias(p.tokens, i)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,6 +104,22 @@ fn generate_fn(tokens []Token, i int) string {
|
||||||
return out.str()
|
return out.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_alias(tokens []Token, i int) string {
|
||||||
|
mut out := strings.new_builder(100)
|
||||||
|
mut tok := tokens[i]
|
||||||
|
for i < tokens.len-1 {
|
||||||
|
out.write(tok.str())
|
||||||
|
out.write(' ')
|
||||||
|
if tok.line_nr != tokens[i+1].line_nr {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
tok = tokens[i]
|
||||||
|
}
|
||||||
|
out.writeln('\n')
|
||||||
|
return out.str()
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_const(tokens []Token, i int) string {
|
fn generate_const(tokens []Token, i int) string {
|
||||||
mut out := strings.new_builder(100)
|
mut out := strings.new_builder(100)
|
||||||
mut tok := tokens[i]
|
mut tok := tokens[i]
|
||||||
|
@ -137,148 +152,4 @@ fn generate_type(tokens []Token, i int) string {
|
||||||
return out.str()
|
return out.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fn (v &V) generate_vh_old() {
|
|
||||||
println('\n\n\n\nGenerating a V header file for module `$v.mod`')
|
|
||||||
mod_path := v.mod.replace('.', os.path_separator)
|
|
||||||
dir := if v.dir.starts_with('vlib') {
|
|
||||||
'$v_modules_path${os.path_separator}$v.dir'
|
|
||||||
} else {
|
|
||||||
'$v_modules_path${os.path_separator}$mod_path'
|
|
||||||
}
|
|
||||||
path := dir + '.vh'
|
|
||||||
pdir := dir.all_before_last(os.path_separator)
|
|
||||||
if !os.dir_exists(pdir) {
|
|
||||||
os.mkdir_all(pdir)
|
|
||||||
// os.mkdir(os.realpath(dir))
|
|
||||||
}
|
|
||||||
file := os.create(path) or { panic(err) }
|
|
||||||
// Consts
|
|
||||||
mod_def := if v.mod.contains('.') { v.mod.all_after('.') } else { v.mod }
|
|
||||||
file.writeln('// $v.mod module header \n')
|
|
||||||
file.writeln('module $mod_def')
|
|
||||||
file.writeln('// Consts')
|
|
||||||
if v.table.consts.len > 0 {
|
|
||||||
file.writeln('const (')
|
|
||||||
for i, c in v.table.consts {
|
|
||||||
if c.mod != v.mod {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// println('$i $c.name')
|
|
||||||
//if !c.name.contains('__') {
|
|
||||||
//continue
|
|
||||||
//}
|
|
||||||
name := c.name.all_after('__')
|
|
||||||
typ := v_type_str(c.typ)
|
|
||||||
file.writeln('\t$name $typ')
|
|
||||||
}
|
|
||||||
file.writeln(')\n')
|
|
||||||
// Globals
|
|
||||||
for var in v.table.consts {
|
|
||||||
if var.mod != v.mod {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !var.is_global {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name := var.name.all_after('__')
|
|
||||||
typ := v_type_str(var.typ)
|
|
||||||
file.writeln('__global $name $typ')
|
|
||||||
}
|
|
||||||
file.writeln('\n')
|
|
||||||
}
|
|
||||||
// Types
|
|
||||||
file.writeln('// Types')
|
|
||||||
for _, typ in v.table.typesmap {
|
|
||||||
//println(typ.name)
|
|
||||||
if typ.mod != v.mod && typ.mod != ''{ // int, string etc mod == ''
|
|
||||||
// println('skipping type "$typ.name"')
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if typ.name.contains('_V_MulRet') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mut name := typ.name
|
|
||||||
if typ.name.contains('__') {
|
|
||||||
name = typ.name.all_after('__')
|
|
||||||
}
|
|
||||||
// type alias
|
|
||||||
if typ.parent != '' && typ.cat == .alias {
|
|
||||||
parent := v_type_str(typ.parent)
|
|
||||||
file.writeln('type $typ.name $parent')
|
|
||||||
}
|
|
||||||
if typ.cat in [TypeCategory.struct_, .c_struct] {
|
|
||||||
c := if typ.is_c { 'C.' } else { '' }
|
|
||||||
file.writeln('struct ${c}$name {')
|
|
||||||
// Private fields
|
|
||||||
for field in typ.fields {
|
|
||||||
if field.access_mod == .public {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
field_type := v_type_str(field.typ).replace('*', '&')
|
|
||||||
file.writeln('\t$field.name $field_type')
|
|
||||||
}
|
|
||||||
//file.writeln('pub:')
|
|
||||||
mut public_str := ''
|
|
||||||
for field in typ.fields {
|
|
||||||
if field.access_mod == .private {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
field_type := v_type_str(field.typ).replace('*', '&')
|
|
||||||
public_str += '\t$field.name $field_type\n'
|
|
||||||
//file.writeln('\t$field.name $field_type')
|
|
||||||
}
|
|
||||||
if public_str != '' {
|
|
||||||
file.writeln('pub:' + public_str)
|
|
||||||
}
|
|
||||||
file.writeln('}\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Functions & methods
|
|
||||||
file.writeln('// Functions')
|
|
||||||
// Public first
|
|
||||||
mut fns := []Fn
|
|
||||||
// TODO fns := v.table.fns.filter(.mod == v.mod)
|
|
||||||
for _, f in v.table.fns {
|
|
||||||
if f.mod == v.mod || f.mod == ''{
|
|
||||||
fns << f
|
|
||||||
} else {
|
|
||||||
//println('skipping fn $f.name mod=$f.mod')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, f in fns {
|
|
||||||
if !f.is_public {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
file.writeln(f.v_definition())
|
|
||||||
}
|
|
||||||
// Private
|
|
||||||
for _, f in fns {
|
|
||||||
if f.is_public {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
file.writeln(f.v_definition())
|
|
||||||
}
|
|
||||||
// Methods
|
|
||||||
file.writeln('\n// Methods //////////////////')
|
|
||||||
for _, typ in v.table.typesmap {
|
|
||||||
if typ.mod != v.mod && !(v.mod == 'builtin' && typ.mod == '') {
|
|
||||||
// println('skipping method typ $typ.name mod=$typ.mod')
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for method in typ.methods {
|
|
||||||
file.writeln(method.v_definition())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
/*
|
|
||||||
for i, p in v.parsers {
|
|
||||||
if v.parsers[i].vh_lines.len > 0 {
|
|
||||||
os.write_file(p.file_name +'.vh', v.parsers[i].vh_lines.join('\n'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
|
@ -508,6 +508,7 @@ fn (p mut Parser) import_statement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) const_decl() {
|
fn (p mut Parser) const_decl() {
|
||||||
|
//println('const decl $p.file_path')
|
||||||
is_pub := p.tok == .key_pub
|
is_pub := p.tok == .key_pub
|
||||||
if is_pub {
|
if is_pub {
|
||||||
p.next()
|
p.next()
|
||||||
|
@ -534,10 +535,16 @@ fn (p mut Parser) const_decl() {
|
||||||
name = p.prepend_mod(name)
|
name = p.prepend_mod(name)
|
||||||
mut typ := ''
|
mut typ := ''
|
||||||
if p.is_vh {
|
if p.is_vh {
|
||||||
// .vh files don't have const values, just types: `const (a int)`
|
//println('CONST VH $p.file_path')
|
||||||
|
// .vh files may not have const values, just types: `const (a int)`
|
||||||
if p.tok == .assign {
|
if p.tok == .assign {
|
||||||
p.next()
|
p.next()
|
||||||
|
// Otherwise parse the expression to get its type,
|
||||||
|
// but don't generate it. Const's value is generated
|
||||||
|
// in "module.o".
|
||||||
|
p.cgen.nogen = true
|
||||||
typ = p.expression()
|
typ = p.expression()
|
||||||
|
p.cgen.nogen = false
|
||||||
} else {
|
} else {
|
||||||
typ = p.get_type()
|
typ = p.get_type()
|
||||||
}
|
}
|
||||||
|
@ -566,6 +573,13 @@ fn (p mut Parser) const_decl() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if p.pass == .main && p.cgen.nogen && p.pref.build_mode == .build_module {
|
||||||
|
// We are building module `ui`, but are parsing `gx` right now
|
||||||
|
// (because of nogen). We need to import gx constants with `extern`.
|
||||||
|
//println('extern const mod=$p.mod name=$name')
|
||||||
|
p.cgen.consts << ('extern ' +
|
||||||
|
p.table.cgen_name_type_pair(name, typ)) + ';'
|
||||||
|
}
|
||||||
if p.pass == .main && !p.cgen.nogen {
|
if p.pass == .main && !p.cgen.nogen {
|
||||||
// TODO hack
|
// TODO hack
|
||||||
// cur_line has const's value right now. if it's just a number, then optimize generation:
|
// cur_line has const's value right now. if it's just a number, then optimize generation:
|
||||||
|
@ -584,6 +598,7 @@ fn (p mut Parser) const_decl() {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p.cgen.consts << p.table.cgen_name_type_pair(name, typ) + ';'
|
p.cgen.consts << p.table.cgen_name_type_pair(name, typ) + ';'
|
||||||
|
//println('adding to init "$name"')
|
||||||
p.cgen.consts_init << '$name = $p.cgen.cur_line;'
|
p.cgen.consts_init << '$name = $p.cgen.cur_line;'
|
||||||
}
|
}
|
||||||
p.cgen.resetln('')
|
p.cgen.resetln('')
|
||||||
|
|
|
@ -81,7 +81,7 @@ fn (p mut Parser) struct_decl() {
|
||||||
typ.is_placeholder = false
|
typ.is_placeholder = false
|
||||||
typ.cat = cat
|
typ.cat = cat
|
||||||
typ.parent = objc_parent
|
typ.parent = objc_parent
|
||||||
typ.is_public = is_pub
|
typ.is_public = is_pub || p.is_vh
|
||||||
p.table.rewrite_type(typ)
|
p.table.rewrite_type(typ)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -91,7 +91,7 @@ fn (p mut Parser) struct_decl() {
|
||||||
is_c: is_c
|
is_c: is_c
|
||||||
cat: cat
|
cat: cat
|
||||||
parent: objc_parent
|
parent: objc_parent
|
||||||
is_public: is_pub
|
is_public: is_pub || p.is_vh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Struct `C.Foo` declaration, no body
|
// Struct `C.Foo` declaration, no body
|
||||||
|
|
|
@ -65,12 +65,12 @@ Commands:
|
||||||
run <file.v> Build and execute the V program in file.v. You can add arguments for the V program *after* the file name.
|
run <file.v> Build and execute the V program in file.v. You can add arguments for the V program *after* the file name.
|
||||||
build <module> Compile a module into an object file.
|
build <module> Compile a module into an object file.
|
||||||
runrepl Run the V REPL. If V is running in a tty terminal, the REPL is interactive, otherwise it just reads from stdin.
|
runrepl Run the V REPL. If V is running in a tty terminal, the REPL is interactive, otherwise it just reads from stdin.
|
||||||
symlink Useful on unix systems. Symlinks the current V executable to /usr/local/bin/v, so that V is globally available.
|
symlink Useful on Unix systems. Symlinks the current V executable to /usr/local/bin/v, so that V is globally available.
|
||||||
install <module> Install a user module from https://vpm.vlang.io/.
|
install <module> Install a user module from https://vpm.vlang.io/.
|
||||||
test v Run all V test files, and compile all V examples.
|
test v Run all V test files, and compile all V examples.
|
||||||
test folder/ Run all V test files located in the folder and its subfolders. You can also pass individual _test.v files too.
|
test folder/ Run all V test files located in the folder and its subfolders. You can also pass individual _test.v files too.
|
||||||
fmt Run vfmt to format the source code. [wip]
|
fmt Run vfmt to format the source code. [wip]
|
||||||
doc Run vdoc over the source code and produce documentation. [wip]
|
doc Run vdoc over the source code and produce documentation.
|
||||||
translate Translates C to V. [wip, will be available in V 0.3]
|
translate Translates C to V. [wip, will be available in V 0.3]
|
||||||
'
|
'
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,6 +4,7 @@ module darwin
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
#flag -framework Cocoa
|
#flag -framework Cocoa
|
||||||
|
#flag -framework Carbon
|
||||||
|
|
||||||
struct C.NSString { }
|
struct C.NSString { }
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ pub const (
|
||||||
path_separator = '/'
|
path_separator = '/'
|
||||||
)
|
)
|
||||||
|
|
||||||
fn init_os_args(argc int, argv &byteptr) []string {
|
pub fn init_os_args(argc int, argv &byteptr) []string {
|
||||||
mut args := []string
|
mut args := []string
|
||||||
for i in 0 .. argc {
|
for i in 0 .. argc {
|
||||||
args << string(argv[i])
|
args << string(argv[i])
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
module main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
ui
|
ui
|
||||||
gx
|
gx
|
||||||
|
|
Loading…
Reference in New Issue