mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
fix maps; use maps for storing functions; verify struct initialization
This commit is contained in:
parent
8e6cb1e1c2
commit
5936ab16c8
@ -151,10 +151,9 @@ fn (g mut CGen) register_thread_fn(wrapper_name, wrapper_text, struct_text strin
|
|||||||
fn (c mut V) prof_counters() string {
|
fn (c mut V) prof_counters() string {
|
||||||
mut res := []string
|
mut res := []string
|
||||||
// Global fns
|
// Global fns
|
||||||
for f in c.table.fns {
|
//for f in c.table.fns {
|
||||||
res << 'double ${c.table.cgen_name(f)}_time;'
|
//res << 'double ${c.table.cgen_name(f)}_time;'
|
||||||
// println(f.name)
|
//}
|
||||||
}
|
|
||||||
// Methods
|
// Methods
|
||||||
for typ in c.table.types {
|
for typ in c.table.types {
|
||||||
// println('')
|
// println('')
|
||||||
@ -170,11 +169,10 @@ fn (c mut V) prof_counters() string {
|
|||||||
fn (p mut Parser) print_prof_counters() string {
|
fn (p mut Parser) print_prof_counters() string {
|
||||||
mut res := []string
|
mut res := []string
|
||||||
// Global fns
|
// Global fns
|
||||||
for f in p.table.fns {
|
//for f in p.table.fns {
|
||||||
counter := '${p.table.cgen_name(f)}_time'
|
//counter := '${p.table.cgen_name(f)}_time'
|
||||||
res << 'if ($counter) printf("%%f : $f.name \\n", $counter);'
|
//res << 'if ($counter) printf("%%f : $f.name \\n", $counter);'
|
||||||
// println(f.name)
|
//}
|
||||||
}
|
|
||||||
// Methods
|
// Methods
|
||||||
for typ in p.table.types {
|
for typ in p.table.types {
|
||||||
// println('')
|
// println('')
|
||||||
|
286
compiler/main.v
286
compiler/main.v
@ -59,8 +59,22 @@ enum Pass {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct V {
|
||||||
|
mut:
|
||||||
|
os Os // the OS to build for
|
||||||
|
out_name_c string // name of the temporary C file
|
||||||
|
files []string // all V files that need to be parsed and compiled
|
||||||
|
dir string // directory (or file) being compiled (TODO rename to path?)
|
||||||
|
table *Table // table with types, vars, functions etc
|
||||||
|
cgen *CGen // C code generator
|
||||||
|
pref *Preferences // all the prefrences and settings extracted to a struct for reusability
|
||||||
|
lang_dir string // "~/code/v"
|
||||||
|
out_name string // "program.exe"
|
||||||
|
vroot string
|
||||||
|
}
|
||||||
|
|
||||||
struct Preferences {
|
struct Preferences {
|
||||||
mut:
|
mut:
|
||||||
build_mode BuildMode
|
build_mode BuildMode
|
||||||
nofmt bool // disable vfmt
|
nofmt bool // disable vfmt
|
||||||
is_test bool // `v test string_test.v`
|
is_test bool // `v test string_test.v`
|
||||||
@ -79,22 +93,7 @@ struct Preferences {
|
|||||||
sanitize bool // use Clang's new "-fsanitize" option
|
sanitize bool // use Clang's new "-fsanitize" option
|
||||||
}
|
}
|
||||||
|
|
||||||
struct V {
|
|
||||||
mut:
|
|
||||||
os Os // the OS to build for
|
|
||||||
out_name_c string // name of the temporary C file
|
|
||||||
files []string // all V files that need to be parsed and compiled
|
|
||||||
dir string // directory (or file) being compiled (TODO rename to path?)
|
|
||||||
table *Table // table with types, vars, functions etc
|
|
||||||
cgen *CGen // C code generator
|
|
||||||
pref *Preferences // all the prefrences and settings extracted to a struct for reusability
|
|
||||||
lang_dir string // "~/code/v"
|
|
||||||
out_name string // "program.exe"
|
|
||||||
vroot string
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// There's no `flags` module yet, so args have to be parsed manually
|
|
||||||
args := os.args
|
args := os.args
|
||||||
// Print the version and exit.
|
// Print the version and exit.
|
||||||
if '-v' in args || 'version' in args {
|
if '-v' in args || 'version' in args {
|
||||||
@ -142,35 +141,35 @@ fn main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Construct the V object from command line arguments
|
// Construct the V object from command line arguments
|
||||||
mut c := new_v(args)
|
mut v := new_v(args)
|
||||||
if c.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
println(args)
|
println(args)
|
||||||
}
|
}
|
||||||
// Generate the docs and exit
|
// Generate the docs and exit
|
||||||
if args.contains('doc') {
|
if args.contains('doc') {
|
||||||
// c.gen_doc_html_for_module(args.last())
|
// v.gen_doc_html_for_module(args.last())
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
c.compile()
|
v.compile()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (c mut V) compile() {
|
fn (v mut V) compile() {
|
||||||
mut cgen := c.cgen
|
mut cgen := v.cgen
|
||||||
cgen.genln('// Generated by V')
|
cgen.genln('// Generated by V')
|
||||||
// Add user files to compile
|
// Add user files to compile
|
||||||
c.add_user_v_files()
|
v.add_user_v_files()
|
||||||
if c.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
println('all .v files:')
|
println('all .v files:')
|
||||||
println(c.files)
|
println(v.files)
|
||||||
}
|
}
|
||||||
// First pass (declarations)
|
// First pass (declarations)
|
||||||
for file in c.files {
|
for file in v.files {
|
||||||
mut p := c.new_parser(file, RUN_DECLS)
|
mut p := v.new_parser(file, RUN_DECLS)
|
||||||
p.parse()
|
p.parse()
|
||||||
}
|
}
|
||||||
// Main pass
|
// Main pass
|
||||||
cgen.run = RUN_MAIN
|
cgen.run = RUN_MAIN
|
||||||
if c.pref.is_play {
|
if v.pref.is_play {
|
||||||
cgen.genln('#define VPLAY (1) ')
|
cgen.genln('#define VPLAY (1) ')
|
||||||
}
|
}
|
||||||
cgen.genln('
|
cgen.genln('
|
||||||
@ -242,31 +241,31 @@ byteptr g_str_buf;
|
|||||||
int load_so(byteptr);
|
int load_so(byteptr);
|
||||||
void reload_so();
|
void reload_so();
|
||||||
void init_consts();')
|
void init_consts();')
|
||||||
imports_json := c.table.imports.contains('json')
|
imports_json := v.table.imports.contains('json')
|
||||||
// TODO remove global UI hack
|
// TODO remove global UI hack
|
||||||
if c.os == MAC && ((c.pref.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) ||
|
if v.os == MAC && ((v.pref.build_mode == EMBED_VLIB && v.table.imports.contains('ui')) ||
|
||||||
(c.pref.build_mode == BUILD && c.dir.contains('/ui'))) {
|
(v.pref.build_mode == BUILD && v.dir.contains('/ui'))) {
|
||||||
cgen.genln('id defaultFont = 0; // main.v')
|
cgen.genln('id defaultFont = 0; // main.v')
|
||||||
}
|
}
|
||||||
// TODO remove ugly .c include once V has its own json parser
|
// TODO remove ugly .c include once V has its own json parser
|
||||||
// Embed cjson either in embedvlib or in json.o
|
// Embed cjson either in embedvlib or in json.o
|
||||||
if imports_json && c.pref.build_mode == EMBED_VLIB ||
|
if imports_json && v.pref.build_mode == EMBED_VLIB ||
|
||||||
(c.pref.build_mode == BUILD && c.out_name.contains('json.o')) {
|
(v.pref.build_mode == BUILD && v.out_name.contains('json.o')) {
|
||||||
cgen.genln('#include "cJSON.c" ')
|
cgen.genln('#include "cJSON.c" ')
|
||||||
}
|
}
|
||||||
// We need the cjson header for all the json decoding user will do in default mode
|
// We need the cjson header for all the json decoding user will do in default mode
|
||||||
if c.pref.build_mode == DEFAULT_MODE {
|
if v.pref.build_mode == DEFAULT_MODE {
|
||||||
if imports_json {
|
if imports_json {
|
||||||
cgen.genln('#include "cJSON.h"')
|
cgen.genln('#include "cJSON.h"')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.pref.build_mode == EMBED_VLIB || c.pref.build_mode == DEFAULT_MODE {
|
if v.pref.build_mode == EMBED_VLIB || v.pref.build_mode == DEFAULT_MODE {
|
||||||
// If we declare these for all modes, then when running `v a.v` we'll get
|
// If we declare these for all modes, then when running `v a.v` we'll get
|
||||||
// `/usr/bin/ld: multiple definition of 'total_m'`
|
// `/usr/bin/ld: multiple definition of 'total_m'`
|
||||||
// TODO
|
// TODO
|
||||||
//cgen.genln('i64 total_m = 0; // For counting total RAM allocated')
|
//cgen.genln('i64 total_m = 0; // For counting total RAM allocated')
|
||||||
cgen.genln('int g_test_ok = 1; ')
|
cgen.genln('int g_test_ok = 1; ')
|
||||||
if c.table.imports.contains('json') {
|
if v.table.imports.contains('json') {
|
||||||
cgen.genln('
|
cgen.genln('
|
||||||
#define js_get(object, key) cJSON_GetObjectItemCaseSensitive((object), (key))
|
#define js_get(object, key) cJSON_GetObjectItemCaseSensitive((object), (key))
|
||||||
')
|
')
|
||||||
@ -278,16 +277,16 @@ void init_consts();')
|
|||||||
cgen.genln('/*================================== FNS =================================*/')
|
cgen.genln('/*================================== FNS =================================*/')
|
||||||
cgen.genln('this line will be replaced with definitions')
|
cgen.genln('this line will be replaced with definitions')
|
||||||
defs_pos := cgen.lines.len - 1
|
defs_pos := cgen.lines.len - 1
|
||||||
for file in c.files {
|
for file in v.files {
|
||||||
mut p := c.new_parser(file, RUN_MAIN)
|
mut p := v.new_parser(file, RUN_MAIN)
|
||||||
p.parse()
|
p.parse()
|
||||||
// p.g.gen_x64()
|
// p.g.gen_x64()
|
||||||
// Format all files (don't format automatically generated vlib headers)
|
// Format all files (don't format automatically generated vlib headers)
|
||||||
if !c.pref.nofmt && !file.contains('/vlib/') {
|
if !v.pref.nofmt && !file.contains('/vlib/') {
|
||||||
// new vfmt is not ready yet
|
// new vfmt is not ready yet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.log('Done parsing.')
|
v.log('Done parsing.')
|
||||||
// Write everything
|
// Write everything
|
||||||
mut d := new_string_builder(10000)// Just to avoid some unnecessary allocations
|
mut d := new_string_builder(10000)// Just to avoid some unnecessary allocations
|
||||||
d.writeln(cgen.includes.join_lines())
|
d.writeln(cgen.includes.join_lines())
|
||||||
@ -298,14 +297,14 @@ void init_consts();')
|
|||||||
d.writeln(cgen.fns.join_lines())
|
d.writeln(cgen.fns.join_lines())
|
||||||
d.writeln(cgen.consts.join_lines())
|
d.writeln(cgen.consts.join_lines())
|
||||||
d.writeln(cgen.thread_args.join_lines())
|
d.writeln(cgen.thread_args.join_lines())
|
||||||
if c.pref.is_prof {
|
if v.pref.is_prof {
|
||||||
d.writeln('; // Prof counters:')
|
d.writeln('; // Prof counters:')
|
||||||
d.writeln(c.prof_counters())
|
d.writeln(v.prof_counters())
|
||||||
}
|
}
|
||||||
dd := d.str()
|
dd := d.str()
|
||||||
cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile
|
cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile
|
||||||
// if c.build_mode in [.default, .embed_vlib] {
|
// if v.build_mode in [.default, .embed_vlib] {
|
||||||
if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == EMBED_VLIB {
|
if v.pref.build_mode == DEFAULT_MODE || v.pref.build_mode == EMBED_VLIB {
|
||||||
// vlib can't have `init_consts()`
|
// vlib can't have `init_consts()`
|
||||||
cgen.genln('void init_consts() { g_str_buf=malloc(1000); ${cgen.consts_init.join_lines()} }')
|
cgen.genln('void init_consts() { g_str_buf=malloc(1000); ${cgen.consts_init.join_lines()} }')
|
||||||
// _STR function can't be defined in vlib
|
// _STR function can't be defined in vlib
|
||||||
@ -345,29 +344,31 @@ string _STR_TMP(const char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
// Make sure the main function exists
|
// Make sure the main function exists
|
||||||
// Obviously we don't need it in libraries
|
// Obviously we don't need it in libraries
|
||||||
if c.pref.build_mode != BUILD {
|
if v.pref.build_mode != BUILD {
|
||||||
if !c.table.main_exists() && !c.pref.is_test {
|
if !v.table.main_exists() && !v.pref.is_test {
|
||||||
// It can be skipped in single file programs
|
// It can be skipped in single file programs
|
||||||
if c.pref.is_script {
|
if v.pref.is_script {
|
||||||
//println('Generating main()...')
|
//println('Generating main()...')
|
||||||
cgen.genln('int main() { $cgen.fn_main; return 0; }')
|
cgen.genln('int main() { $cgen.fn_main; return 0; }')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
println('panic: function `main` is undeclared in the main module')
|
println('panic: function `main` is undeclared in the main module')
|
||||||
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Generate `main` which calls every single test function
|
// Generate `main` which calls every single test function
|
||||||
else if c.pref.is_test {
|
else if v.pref.is_test {
|
||||||
cgen.genln('int main() { init_consts();')
|
cgen.genln('int main() { init_consts();')
|
||||||
for v in c.table.fns {
|
for entry in v.table.fns.entries {
|
||||||
if v.name.starts_with('test_') {
|
f := v.table.fns[entry.key]
|
||||||
cgen.genln('$v.name();')
|
if f.name.starts_with('test_') {
|
||||||
|
cgen.genln('$f.name();')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cgen.genln('return g_test_ok == 0; }')
|
cgen.genln('return g_test_ok == 0; }')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.pref.is_live {
|
if v.pref.is_live {
|
||||||
cgen.genln(' int load_so(byteptr path) {
|
cgen.genln(' int load_so(byteptr path) {
|
||||||
printf("load_so %s\\n", path); dlclose(live_lib); live_lib = dlopen(path, RTLD_LAZY);
|
printf("load_so %s\\n", path); dlclose(live_lib); live_lib = dlopen(path, RTLD_LAZY);
|
||||||
if (!live_lib) {puts("open failed"); exit(1); return 0;}
|
if (!live_lib) {puts("open failed"); exit(1); return 0;}
|
||||||
@ -378,70 +379,71 @@ string _STR_TMP(const char *fmt, ...) {
|
|||||||
cgen.genln('return 1; }')
|
cgen.genln('return 1; }')
|
||||||
}
|
}
|
||||||
cgen.save()
|
cgen.save()
|
||||||
if c.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
c.log('flags=')
|
v.log('flags=')
|
||||||
println(c.table.flags)
|
println(v.table.flags)
|
||||||
}
|
}
|
||||||
c.cc()
|
v.cc()
|
||||||
if c.pref.is_test || c.pref.is_run {
|
if v.pref.is_test || v.pref.is_run {
|
||||||
if true || c.pref.is_verbose {
|
if true || v.pref.is_verbose {
|
||||||
println('============ running $c.out_name ============')
|
println('============ running $v.out_name ============')
|
||||||
}
|
}
|
||||||
mut cmd := if c.out_name.starts_with('/') {
|
mut cmd := if v.out_name.starts_with('/') {
|
||||||
c.out_name
|
v.out_name
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
'./' + c.out_name
|
'./' + v.out_name
|
||||||
}
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
cmd = c.out_name
|
cmd = v.out_name
|
||||||
}
|
}
|
||||||
if os.args.len > 3 {
|
if os.args.len > 3 {
|
||||||
cmd += ' ' + os.args.right(3).join(' ')
|
cmd += ' ' + os.args.right(3).join(' ')
|
||||||
}
|
}
|
||||||
ret := os.system(cmd)
|
ret := os.system(cmd)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
|
if !v.pref.is_test {
|
||||||
s := os.exec(cmd)
|
s := os.exec(cmd)
|
||||||
println(s)
|
println(s)
|
||||||
println('failed to run the compiled program, this should never happen')
|
println('failed to run the compiled program')
|
||||||
println('please submit a GitHub issue')
|
}
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (c mut V) cc() {
|
fn (v mut V) cc() {
|
||||||
linux_host := os.user_os() == 'linux'
|
linux_host := os.user_os() == 'linux'
|
||||||
c.log('cc() isprod=$c.pref.is_prod outname=$c.out_name')
|
v.log('cc() isprod=$v.pref.is_prod outname=$v.out_name')
|
||||||
mut a := ['-w']// arguments for the C compiler
|
mut a := ['-w']// arguments for the C compiler
|
||||||
flags := c.table.flags.join(' ')
|
flags := v.table.flags.join(' ')
|
||||||
/*
|
/*
|
||||||
mut shared := ''
|
mut shared := ''
|
||||||
if c.pref.is_so {
|
if v.pref.is_so {
|
||||||
a << '-shared'// -Wl,-z,defs'
|
a << '-shared'// -Wl,-z,defs'
|
||||||
c.out_name = c.out_name + '.so'
|
v.out_name = v.out_name + '.so'
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if c.pref.is_prod {
|
if v.pref.is_prod {
|
||||||
a << '-O2'
|
a << '-O2'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
a << '-g'
|
a << '-g'
|
||||||
}
|
}
|
||||||
mut libs := ''// builtin.o os.o http.o etc
|
mut libs := ''// builtin.o os.o http.o etc
|
||||||
if c.pref.build_mode == BUILD {
|
if v.pref.build_mode == BUILD {
|
||||||
a << '-c'
|
a << '-c'
|
||||||
}
|
}
|
||||||
else if c.pref.build_mode == EMBED_VLIB {
|
else if v.pref.build_mode == EMBED_VLIB {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
else if c.pref.build_mode == DEFAULT_MODE {
|
else if v.pref.build_mode == DEFAULT_MODE {
|
||||||
libs = '$TmpPath/vlib/builtin.o'
|
libs = '$TmpPath/vlib/builtin.o'
|
||||||
if !os.file_exists(libs) {
|
if !os.file_exists(libs) {
|
||||||
println('`builtin.o` not found')
|
println('`builtin.o` not found')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
for imp in c.table.imports {
|
for imp in v.table.imports {
|
||||||
if imp == 'webview' {
|
if imp == 'webview' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -451,62 +453,62 @@ fn (c mut V) cc() {
|
|||||||
// -I flags
|
// -I flags
|
||||||
/*
|
/*
|
||||||
mut args := ''
|
mut args := ''
|
||||||
for flag in c.table.flags {
|
for flag in v.table.flags {
|
||||||
if !flag.starts_with('-l') {
|
if !flag.starts_with('-l') {
|
||||||
args += flag
|
args += flag
|
||||||
args += ' '
|
args += ' '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if c.pref.sanitize {
|
if v.pref.sanitize {
|
||||||
a << '-fsanitize=leak'
|
a << '-fsanitize=leak'
|
||||||
}
|
}
|
||||||
// Cross compiling linux
|
// Cross compiling linux
|
||||||
sysroot := '/Users/alex/tmp/lld/linuxroot/'
|
sysroot := '/Users/alex/tmp/lld/linuxroot/'
|
||||||
if c.os == LINUX && !linux_host {
|
if v.os == LINUX && !linux_host {
|
||||||
// Build file.o
|
// Build file.o
|
||||||
a << '-c --sysroot=$sysroot -target x86_64-linux-gnu'
|
a << '-c --sysroot=$sysroot -target x86_64-linux-gnu'
|
||||||
// Right now `out_name` can be `file`, not `file.o`
|
// Right now `out_name` can be `file`, not `file.o`
|
||||||
if !c.out_name.ends_with('.o') {
|
if !v.out_name.ends_with('.o') {
|
||||||
c.out_name = c.out_name + '.o'
|
v.out_name = v.out_name + '.o'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Cross compiling windows
|
// Cross compiling windows
|
||||||
// sysroot := '/Users/alex/tmp/lld/linuxroot/'
|
// sysroot := '/Users/alex/tmp/lld/linuxroot/'
|
||||||
// Output executable name
|
// Output executable name
|
||||||
// else {
|
// else {
|
||||||
a << '-o $c.out_name'
|
a << '-o $v.out_name'
|
||||||
// The C file we are compiling
|
// The C file we are compiling
|
||||||
a << '$TmpPath/$c.out_name_c'
|
a << '$TmpPath/$v.out_name_c'
|
||||||
// }
|
// }
|
||||||
// Min macos version is mandatory I think?
|
// Min macos version is mandatory I think?
|
||||||
if c.os == MAC {
|
if v.os == MAC {
|
||||||
a << '-mmacosx-version-min=10.7'
|
a << '-mmacosx-version-min=10.7'
|
||||||
}
|
}
|
||||||
a << flags
|
a << flags
|
||||||
a << libs
|
a << libs
|
||||||
// macOS code can include objective C TODO remove once objective C is replaced with C
|
// macOS code can include objective C TODO remove once objective C is replaced with C
|
||||||
if c.os == MAC {
|
if v.os == MAC {
|
||||||
a << '-x objective-c'
|
a << '-x objective-c'
|
||||||
}
|
}
|
||||||
// Without these libs compilation will fail on Linux
|
// Without these libs compilation will fail on Linux
|
||||||
if c.os == LINUX && c.pref.build_mode != BUILD {
|
if v.os == LINUX && v.pref.build_mode != BUILD {
|
||||||
a << '-lm -ldl -lpthread'
|
a << '-lm -ldl -lpthread'
|
||||||
}
|
}
|
||||||
// Find clang executable
|
// Find clang executable
|
||||||
fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
|
//fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
|
||||||
args := a.join(' ')
|
args := a.join(' ')
|
||||||
mut cmd := if os.file_exists(fast_clang) {
|
//mut cmd := if os.file_exists(fast_clang) {
|
||||||
'$fast_clang $args'
|
//'$fast_clang $args'
|
||||||
}
|
//}
|
||||||
else {
|
//else {
|
||||||
'cc $args'
|
mut cmd := 'cc $args'
|
||||||
}
|
//}
|
||||||
$if windows {
|
$if windows {
|
||||||
cmd = 'gcc $args'
|
cmd = 'gcc $args'
|
||||||
}
|
}
|
||||||
// Print the C command
|
// Print the C command
|
||||||
if c.pref.show_c_cmd || c.pref.is_verbose {
|
if v.pref.show_c_cmd || v.pref.is_verbose {
|
||||||
println('\n==========\n$cmd\n=========\n')
|
println('\n==========\n$cmd\n=========\n')
|
||||||
}
|
}
|
||||||
// Run
|
// Run
|
||||||
@ -517,29 +519,29 @@ mut args := ''
|
|||||||
panic('clang error')
|
panic('clang error')
|
||||||
}
|
}
|
||||||
// Link it if we are cross compiling and need an executable
|
// Link it if we are cross compiling and need an executable
|
||||||
if c.os == LINUX && !linux_host && c.pref.build_mode != BUILD {
|
if v.os == LINUX && !linux_host && v.pref.build_mode != BUILD {
|
||||||
c.out_name = c.out_name.replace('.o', '')
|
v.out_name = v.out_name.replace('.o', '')
|
||||||
obj_file := c.out_name + '.o'
|
obj_file := v.out_name + '.o'
|
||||||
println('linux obj_file=$obj_file out_name=$c.out_name')
|
println('linux obj_file=$obj_file out_name=$v.out_name')
|
||||||
ress := os.exec('/usr/local/Cellar/llvm/8.0.0/bin/ld.lld --sysroot=$sysroot ' +
|
ress := os.exec('/usr/local/Cellar/llvm/8.0.0/bin/ld.lld --sysroot=$sysroot ' +
|
||||||
'-v -o $c.out_name ' +
|
'-v -o $v.out_name ' +
|
||||||
'-m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 ' +
|
'-m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 ' +
|
||||||
'/usr/lib/x86_64-linux-gnu/crt1.o ' +
|
'/usr/lib/x86_64-linux-gnu/crt1.o ' +
|
||||||
'$sysroot/lib/x86_64-linux-gnu/libm-2.28.a ' +
|
'$sysroot/lib/x86_64-linux-gnu/libm-2.28.a ' +
|
||||||
'/usr/lib/x86_64-linux-gnu/crti.o ' +
|
'/usr/lib/x86_64-linux-gnu/crti.o ' +
|
||||||
obj_file +
|
obj_file +
|
||||||
' /usr/lib/x86_64-linux-gnu/libc.so ' +
|
' /usr/lib/x86_64-linux-gnu/libv.so ' +
|
||||||
'/usr/lib/x86_64-linux-gnu/crtn.o')
|
'/usr/lib/x86_64-linux-gnu/crtn.o')
|
||||||
println(ress)
|
println(ress)
|
||||||
if ress.contains('error:') {
|
if ress.contains('error:') {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
println('linux cross compilation done. resulting binary: "$c.out_name"')
|
println('linux cross compilation done. resulting binary: "$v.out_name"')
|
||||||
}
|
}
|
||||||
//os.rm('$TmpPath/$c.out_name_c')
|
//os.rm('$TmpPath/$v.out_name_c')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (c &V) v_files_from_dir(dir string) []string {
|
fn (v &V) v_files_from_dir(dir string) []string {
|
||||||
mut res := []string
|
mut res := []string
|
||||||
if !os.file_exists(dir) {
|
if !os.file_exists(dir) {
|
||||||
panic('$dir doesn\'t exist')
|
panic('$dir doesn\'t exist')
|
||||||
@ -547,38 +549,38 @@ fn (c &V) v_files_from_dir(dir string) []string {
|
|||||||
panic('$dir isn\'t a directory')
|
panic('$dir isn\'t a directory')
|
||||||
}
|
}
|
||||||
mut files := os.ls(dir)
|
mut files := os.ls(dir)
|
||||||
if c.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
println('v_files_from_dir ("$dir")')
|
println('v_files_from_dir ("$dir")')
|
||||||
}
|
}
|
||||||
// println(files.len)
|
// println(files.len)
|
||||||
// println(files)
|
// println(files)
|
||||||
files.sort()
|
files.sort()
|
||||||
for file in files {
|
for file in files {
|
||||||
c.log('F=$file')
|
v.log('F=$file')
|
||||||
if !file.ends_with('.v') && !file.ends_with('.vh') {
|
if !file.ends_with('.v') && !file.ends_with('.vh') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if file.ends_with('_test.v') {
|
if file.ends_with('_test.v') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if file.ends_with('_win.v') && c.os != WINDOWS {
|
if file.ends_with('_win.v') && v.os != WINDOWS {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if file.ends_with('_lin.v') && c.os != LINUX {
|
if file.ends_with('_lin.v') && v.os != LINUX {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if file.ends_with('_mac.v') && c.os != MAC {
|
if file.ends_with('_mav.v') && v.os != MAC {
|
||||||
lin_file := file.replace('_mac.v', '_lin.v')
|
lin_file := file.replace('_mav.v', '_lin.v')
|
||||||
// println('lin_file="$lin_file"')
|
// println('lin_file="$lin_file"')
|
||||||
// If there are both _mac.v and _lin.v, don't use _mac.v
|
// If there are both _mav.v and _lin.v, don't use _mav.v
|
||||||
if os.file_exists('$dir/$lin_file') {
|
if os.file_exists('$dir/$lin_file') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
else if c.os == WINDOWS {
|
else if v.os == WINDOWS {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If there's only _mac.v, then it can be used on Linux too
|
// If there's only _mav.v, then it can be used on Linux too
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res << '$dir/$file'
|
res << '$dir/$file'
|
||||||
@ -587,9 +589,9 @@ fn (c &V) v_files_from_dir(dir string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parses imports, adds necessary libs, and then user files
|
// Parses imports, adds necessary libs, and then user files
|
||||||
fn (c mut V) add_user_v_files() {
|
fn (v mut V) add_user_v_files() {
|
||||||
mut dir := c.dir
|
mut dir := v.dir
|
||||||
c.log('add_v_files($dir)')
|
v.log('add_v_files($dir)')
|
||||||
// Need to store user files separately, because they have to be added after libs, but we dont know
|
// Need to store user files separately, because they have to be added after libs, but we dont know
|
||||||
// which libs need to be added yet
|
// which libs need to be added yet
|
||||||
mut user_files := []string
|
mut user_files := []string
|
||||||
@ -609,7 +611,7 @@ fn (c mut V) add_user_v_files() {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Add files from the dir user is compiling (only .v files)
|
// Add files from the dir user is compiling (only .v files)
|
||||||
files := c.v_files_from_dir(dir)
|
files := v.v_files_from_dir(dir)
|
||||||
for file in files {
|
for file in files {
|
||||||
user_files << file
|
user_files << file
|
||||||
}
|
}
|
||||||
@ -618,65 +620,65 @@ fn (c mut V) add_user_v_files() {
|
|||||||
println('No input .v files')
|
println('No input .v files')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
if c.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
c.log('user_files:')
|
v.log('user_files:')
|
||||||
println(user_files)
|
println(user_files)
|
||||||
}
|
}
|
||||||
// Parse user imports
|
// Parse user imports
|
||||||
for file in user_files {
|
for file in user_files {
|
||||||
mut p := c.new_parser(file, RUN_IMPORTS)
|
mut p := v.new_parser(file, RUN_IMPORTS)
|
||||||
p.parse()
|
p.parse()
|
||||||
}
|
}
|
||||||
// Parse lib imports
|
// Parse lib imports
|
||||||
if c.pref.build_mode == DEFAULT_MODE {
|
if v.pref.build_mode == DEFAULT_MODE {
|
||||||
for i := 0; i < c.table.imports.len; i++ {
|
for i := 0; i < v.table.imports.len; i++ {
|
||||||
pkg := c.table.imports[i]
|
pkg := v.table.imports[i]
|
||||||
vfiles := c.v_files_from_dir('$TmpPath/vlib/$pkg')
|
vfiles := v.v_files_from_dir('$TmpPath/vlib/$pkg')
|
||||||
// Add all imports referenced by these libs
|
// Add all imports referenced by these libs
|
||||||
for file in vfiles {
|
for file in vfiles {
|
||||||
mut p := c.new_parser(file, RUN_IMPORTS)
|
mut p := v.new_parser(file, RUN_IMPORTS)
|
||||||
p.parse()
|
p.parse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO this used to crash compiler?
|
// TODO this used to crash compiler?
|
||||||
// for pkg in c.table.imports {
|
// for pkg in v.table.imports {
|
||||||
for i := 0; i < c.table.imports.len; i++ {
|
for i := 0; i < v.table.imports.len; i++ {
|
||||||
pkg := c.table.imports[i]
|
pkg := v.table.imports[i]
|
||||||
// mut import_path := '$c.lang_dir/$pkg'
|
// mut import_path := '$v.lang_dir/$pkg'
|
||||||
vfiles := c.v_files_from_dir('$c.lang_dir/vlib/$pkg')
|
vfiles := v.v_files_from_dir('$v.lang_dir/vlib/$pkg')
|
||||||
// Add all imports referenced by these libs
|
// Add all imports referenced by these libs
|
||||||
for file in vfiles {
|
for file in vfiles {
|
||||||
mut p := c.new_parser(file, RUN_IMPORTS)
|
mut p := v.new_parser(file, RUN_IMPORTS)
|
||||||
p.parse()
|
p.parse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
c.log('imports:')
|
v.log('imports:')
|
||||||
println(c.table.imports)
|
println(v.table.imports)
|
||||||
}
|
}
|
||||||
// Only now add all combined lib files
|
// Only now add all combined lib files
|
||||||
for pkg in c.table.imports {
|
for pkg in v.table.imports {
|
||||||
mut module_path := '$c.lang_dir/vlib/$pkg'
|
mut module_path := '$v.lang_dir/vlib/$pkg'
|
||||||
// If we are in default mode, we don't parse vlib .v files, but header .vh files in
|
// If we are in default mode, we don't parse vlib .v files, but header .vh files in
|
||||||
// TmpPath/vlib
|
// TmpPath/vlib
|
||||||
// These were generated by vfmt
|
// These were generated by vfmt
|
||||||
if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == BUILD {
|
if v.pref.build_mode == DEFAULT_MODE || v.pref.build_mode == BUILD {
|
||||||
module_path = '$TmpPath/vlib/$pkg'
|
module_path = '$TmpPath/vlib/$pkg'
|
||||||
}
|
}
|
||||||
vfiles := c.v_files_from_dir(module_path)
|
vfiles := v.v_files_from_dir(module_path)
|
||||||
for vfile in vfiles {
|
for vfile in vfiles {
|
||||||
c.files << vfile
|
v.files << vfile
|
||||||
}
|
}
|
||||||
// TODO c.files.append_array(vfiles)
|
// TODO v.files.append_array(vfiles)
|
||||||
}
|
}
|
||||||
// Add user code last
|
// Add user code last
|
||||||
for file in user_files {
|
for file in user_files {
|
||||||
c.files << file
|
v.files << file
|
||||||
}
|
}
|
||||||
// c.files.append_array(user_files)
|
// v.files.append_array(user_files)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_arg(joined_args, arg, def string) string {
|
fn get_arg(joined_args, arg, def string) string {
|
||||||
@ -695,8 +697,8 @@ fn get_arg(joined_args, arg, def string) string {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (c &V) log(s string) {
|
fn (v &V) log(s string) {
|
||||||
if !c.pref.is_verbose {
|
if !v.pref.is_verbose {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
println(s)
|
println(s)
|
||||||
|
@ -763,6 +763,21 @@ fn (p mut Parser) get_type() string {
|
|||||||
p.check(RSBR)
|
p.check(RSBR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// map[string]int
|
||||||
|
if !p.builtin_pkg && p.tok == NAME && p.lit == 'map' {
|
||||||
|
p.next()
|
||||||
|
p.check(LSBR)
|
||||||
|
key_type := p.check_name()
|
||||||
|
if key_type != 'string' {
|
||||||
|
p.error('maps only support string keys for now')
|
||||||
|
}
|
||||||
|
p.check(RSBR)
|
||||||
|
val_type := p.check_name()
|
||||||
|
typ= 'map_$val_type'
|
||||||
|
p.register_map(typ)
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
//
|
||||||
for p.tok == MUL {
|
for p.tok == MUL {
|
||||||
mul = true
|
mul = true
|
||||||
nr_muls++
|
nr_muls++
|
||||||
@ -2345,6 +2360,18 @@ fn (p mut Parser) register_array(typ string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn (p mut Parser) register_map(typ string) {
|
||||||
|
if typ.contains('*') {
|
||||||
|
println('bad map $typ')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !p.table.known_type(typ) {
|
||||||
|
p.register_type_with_parent(typ, 'map')
|
||||||
|
p.cgen.typedefs << 'typedef map $typ;'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (p mut Parser) struct_init(is_c_struct_init bool) string {
|
fn (p mut Parser) struct_init(is_c_struct_init bool) string {
|
||||||
p.is_struct_init = true
|
p.is_struct_init = true
|
||||||
mut typ := p.get_type()
|
mut typ := p.get_type()
|
||||||
@ -2390,11 +2417,12 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string {
|
|||||||
if !t.has_field(field) {
|
if !t.has_field(field) {
|
||||||
p.error('`$t.name` has no field `$field`')
|
p.error('`$t.name` has no field `$field`')
|
||||||
}
|
}
|
||||||
|
f := t.find_field(field)
|
||||||
inited_fields << field
|
inited_fields << field
|
||||||
p.gen('.$field = ')
|
p.gen('.$field = ')
|
||||||
p.check(COLON)
|
p.check(COLON)
|
||||||
p.fspace()
|
p.fspace()
|
||||||
p.expression()
|
p.check_types(p.bool_expression(), f.typ)
|
||||||
if p.tok == COMMA {
|
if p.tok == COMMA {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
@ -2419,7 +2447,7 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string {
|
|||||||
p.error('pointer field `${typ}.${field.name}` must be initialized')
|
p.error('pointer field `${typ}.${field.name}` must be initialized')
|
||||||
}
|
}
|
||||||
def_val := type_default(field_typ)
|
def_val := type_default(field_typ)
|
||||||
if def_val != '' {
|
if def_val != '' && def_val != '{}' {
|
||||||
p.gen('.$field.name = $def_val')
|
p.gen('.$field.name = $def_val')
|
||||||
if i != t.fields.len - 1 {
|
if i != t.fields.len - 1 {
|
||||||
p.gen(',')
|
p.gen(',')
|
||||||
@ -2938,6 +2966,9 @@ fn (p mut Parser) switch_statement() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) assert_statement() {
|
fn (p mut Parser) assert_statement() {
|
||||||
|
if p.first_run() {
|
||||||
|
return
|
||||||
|
}
|
||||||
p.check(ASSERT)
|
p.check(ASSERT)
|
||||||
p.fspace()
|
p.fspace()
|
||||||
tmp := p.get_tmp()
|
tmp := p.get_tmp()
|
||||||
|
@ -8,8 +8,8 @@ struct Table {
|
|||||||
mut:
|
mut:
|
||||||
types []Type
|
types []Type
|
||||||
consts []Var
|
consts []Var
|
||||||
fns []Fn
|
fns map[string]Fn
|
||||||
obf_ids map_int // obf_ids 'myfunction'] == 23
|
obf_ids map[string]int // obf_ids 'myfunction'] == 23
|
||||||
packages []string // List of all modules registered by the application
|
packages []string // List of all modules registered by the application
|
||||||
imports []string // List of all imports
|
imports []string // List of all imports
|
||||||
flags []string // ['-framework Cocoa', '-lglfw3']
|
flags []string // ['-framework Cocoa', '-lglfw3']
|
||||||
@ -112,6 +112,7 @@ fn is_float_type(typ string) bool {
|
|||||||
fn new_table(obfuscate bool) *Table {
|
fn new_table(obfuscate bool) *Table {
|
||||||
mut t := &Table {
|
mut t := &Table {
|
||||||
obf_ids: map[string]int{}
|
obf_ids: map[string]int{}
|
||||||
|
fns: map[string]Fn{}
|
||||||
obfuscate: obfuscate
|
obfuscate: obfuscate
|
||||||
}
|
}
|
||||||
t.register_type('int')
|
t.register_type('int')
|
||||||
@ -186,15 +187,8 @@ fn (p mut Parser) register_global(name, typ string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO PERF O(N) this slows down the comiler a lot!
|
fn (t mut Table) register_fn(new_fn Fn) {
|
||||||
fn (t mut Table) register_fn(f Fn) {
|
t.fns[new_fn.name] = new_fn
|
||||||
// Avoid duplicate fn names TODO why? the name should already be unique?
|
|
||||||
for ff in t.fns {
|
|
||||||
if ff.name == f.name {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.fns << f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (table &Table) known_type(typ string) bool {
|
fn (table &Table) known_type(typ string) bool {
|
||||||
@ -210,24 +204,17 @@ fn (table &Table) known_type(typ string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO PERF O(N) this slows down the compiler a lot!
|
|
||||||
fn (t &Table) find_fn(name string) Fn {
|
fn (t &Table) find_fn(name string) Fn {
|
||||||
for f in t.fns {
|
f := t.fns[name]
|
||||||
if f.name == name {
|
if !isnil(f.name.str) {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Fn{}
|
return Fn{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO PERF O(N) this slows down the compiler a lot!
|
|
||||||
fn (t &Table) known_fn(name string) bool {
|
fn (t &Table) known_fn(name string) bool {
|
||||||
for f in t.fns {
|
f := t.find_fn(name)
|
||||||
if f.name == name {
|
return f.name != ''
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) known_const(name string) bool {
|
fn (t &Table) known_const(name string) bool {
|
||||||
@ -240,7 +227,6 @@ fn (t mut Table) register_type(typ string) {
|
|||||||
if typ.len == 0 {
|
if typ.len == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// println('REGISTER TYPE $typ')
|
|
||||||
for typ2 in t.types {
|
for typ2 in t.types {
|
||||||
if typ2.name == typ {
|
if typ2.name == typ {
|
||||||
return
|
return
|
||||||
@ -553,6 +539,7 @@ fn type_default(typ string) string {
|
|||||||
case 'byte*': return '0'
|
case 'byte*': return '0'
|
||||||
case 'bool': return '0'
|
case 'bool': return '0'
|
||||||
}
|
}
|
||||||
|
return '{}'
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,7 +555,8 @@ fn (t &Table) is_interface(name string) bool {
|
|||||||
|
|
||||||
// Do we have fn main()?
|
// Do we have fn main()?
|
||||||
fn (t &Table) main_exists() bool {
|
fn (t &Table) main_exists() bool {
|
||||||
for f in t.fns {
|
for entry in t.fns.entries {
|
||||||
|
f := t.fns[entry.key]
|
||||||
if f.name == 'main' {
|
if f.name == 'main' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ pub:
|
|||||||
// next *Entry
|
// next *Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_map(cap, elm_size int) map {
|
fn new_map(cap, elm_size int) map {
|
||||||
res := map {
|
res := map {
|
||||||
// len: len,
|
// len: len,
|
||||||
element_size: elm_size
|
element_size: elm_size
|
||||||
@ -59,15 +59,6 @@ fn (m mut map) _set(key string, val voidptr) {
|
|||||||
m.is_sorted = false
|
m.is_sorted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn volt_abs(n int) int {
|
|
||||||
// println('volt_abs($n)')
|
|
||||||
if n < 0 {
|
|
||||||
// println('< 0: -($n)')
|
|
||||||
return -n
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (m map) bs(query string, start, end int, out voidptr) {
|
fn (m map) bs(query string, start, end int, out voidptr) {
|
||||||
// println('bs "$query" $start -> $end')
|
// println('bs "$query" $start -> $end')
|
||||||
mid := start + ((end - start) / 2)
|
mid := start + ((end - start) / 2)
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
|
struct User {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
struct A {
|
struct A {
|
||||||
m map_int
|
m map[string]int
|
||||||
|
users map[string]User
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (a mut A) set(key string, val int) {
|
fn (a mut A) set(key string, val int) {
|
||||||
@ -10,10 +15,19 @@ fn test_map() {
|
|||||||
mut m := map[string]int{}
|
mut m := map[string]int{}
|
||||||
m['hi'] = 80
|
m['hi'] = 80
|
||||||
assert m['hi'] == 80
|
assert m['hi'] == 80
|
||||||
|
////
|
||||||
|
mut users := map[string]User{}
|
||||||
|
users['1'] = User{'Peter'}
|
||||||
|
peter := users['1']
|
||||||
|
assert peter.name == 'Peter'
|
||||||
|
|
||||||
mut a := A{
|
mut a := A{
|
||||||
m: new_map(1, sizeof(int))
|
m: map[string]int{}
|
||||||
|
users: map[string]User{}
|
||||||
}
|
}
|
||||||
|
a.users['Bob'] = User{'Bob'}
|
||||||
|
q := a.users['Bob']
|
||||||
|
assert q.name == 'Bob'
|
||||||
a.m['one'] = 1
|
a.m['one'] = 1
|
||||||
a.set('two', 2)
|
a.set('two', 2)
|
||||||
assert a.m['one'] == 1
|
assert a.m['one'] == 1
|
||||||
|
@ -636,7 +636,6 @@ __global g_ustring_runes []int
|
|||||||
pub fn (s string) ustring_tmp() ustring {
|
pub fn (s string) ustring_tmp() ustring {
|
||||||
mut res := ustring {
|
mut res := ustring {
|
||||||
s: s
|
s: s
|
||||||
runes: 0
|
|
||||||
}
|
}
|
||||||
res.runes = g_ustring_runes
|
res.runes = g_ustring_runes
|
||||||
res.runes.len = s.len
|
res.runes.len = s.len
|
||||||
|
Loading…
Reference in New Issue
Block a user