fmt: remove trailing spaces
parent
8a1324c141
commit
fe2d2bd2a3
284
compiler/fn.v
284
compiler/fn.v
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MaxLocalVars = 50
|
MaxLocalVars = 50
|
||||||
|
@ -30,7 +30,7 @@ mut:
|
||||||
returns_error bool
|
returns_error bool
|
||||||
is_decl bool // type myfn fn(int, int)
|
is_decl bool // type myfn fn(int, int)
|
||||||
defer_text []string
|
defer_text []string
|
||||||
//gen_types []string
|
//gen_types []string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (f &Fn) find_var(name string) Var {
|
fn (f &Fn) find_var(name string) Var {
|
||||||
|
@ -114,12 +114,12 @@ fn new_fn(mod string, is_public bool) *Fn {
|
||||||
// Function signatures are added to the top of the .c file in the first run.
|
// Function signatures are added to the top of the .c file in the first run.
|
||||||
fn (p mut Parser) fn_decl() {
|
fn (p mut Parser) fn_decl() {
|
||||||
p.fgen('fn ')
|
p.fgen('fn ')
|
||||||
//defer { p.fgenln('\n') }
|
//defer { p.fgenln('\n') }
|
||||||
is_pub := p.tok == .key_pub
|
is_pub := p.tok == .key_pub
|
||||||
is_live := p.attr == 'live' && !p.pref.is_so && p.pref.is_live
|
is_live := p.attr == 'live' && !p.pref.is_so && p.pref.is_live
|
||||||
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 is_pub {
|
if is_pub {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ fn (p mut Parser) fn_decl() {
|
||||||
is_mut := p.tok == .key_mut
|
is_mut := p.tok == .key_mut
|
||||||
is_amp := p.tok == .amp
|
is_amp := p.tok == .amp
|
||||||
if is_mut || is_amp {
|
if is_mut || is_amp {
|
||||||
p.check_space(p.tok)
|
p.check_space(p.tok)
|
||||||
}
|
}
|
||||||
receiver_typ = p.get_type()
|
receiver_typ = p.get_type()
|
||||||
T := p.table.find_type(receiver_typ)
|
T := p.table.find_type(receiver_typ)
|
||||||
|
@ -159,7 +159,7 @@ fn (p mut Parser) fn_decl() {
|
||||||
receiver_typ += '*'
|
receiver_typ += '*'
|
||||||
}
|
}
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
p.fspace()
|
p.fspace()
|
||||||
receiver := Var {
|
receiver := Var {
|
||||||
name: receiver_name
|
name: receiver_name
|
||||||
is_arg: true
|
is_arg: true
|
||||||
|
@ -180,7 +180,7 @@ fn (p mut Parser) fn_decl() {
|
||||||
f.name = p.check_name()
|
f.name = p.check_name()
|
||||||
}
|
}
|
||||||
// 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
|
||||||
// is_sig := p.builtin_mod && p.pref.build_mode == default_mode
|
// is_sig := p.builtin_mod && p.pref.build_mode == default_mode
|
||||||
// is_sig := p.pref.build_mode == default_mode && (p.builtin_mod || p.file.contains(LANG_TMP))
|
// is_sig := p.pref.build_mode == default_mode && (p.builtin_mod || p.file.contains(LANG_TMP))
|
||||||
|
@ -228,12 +228,12 @@ fn (p mut Parser) fn_decl() {
|
||||||
p.error('only `T` is allowed as a generic type for now')
|
p.error('only `T` is allowed as a generic type for now')
|
||||||
}
|
}
|
||||||
p.check(.gt)
|
p.check(.gt)
|
||||||
if p.first_pass() {
|
if p.first_pass() {
|
||||||
p.table.register_generic_fn(f.name)
|
p.table.register_generic_fn(f.name)
|
||||||
} else {
|
} else {
|
||||||
//gen_types := p.table.fn_gen_types(f.name)
|
//gen_types := p.table.fn_gen_types(f.name)
|
||||||
//println(gen_types)
|
//println(gen_types)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Args (...)
|
// Args (...)
|
||||||
p.fn_args(mut f)
|
p.fn_args(mut f)
|
||||||
|
@ -252,7 +252,7 @@ fn (p mut Parser) fn_decl() {
|
||||||
typ = p.get_type()
|
typ = p.get_type()
|
||||||
}
|
}
|
||||||
// Translated C code can have empty functions (just definitions)
|
// Translated C code can have empty functions (just definitions)
|
||||||
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) && p.tok != .lcbr
|
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) && p.tok != .lcbr
|
||||||
if is_fn_header {
|
if is_fn_header {
|
||||||
f.is_decl = true
|
f.is_decl = true
|
||||||
}
|
}
|
||||||
|
@ -279,12 +279,12 @@ fn (p mut Parser) fn_decl() {
|
||||||
dll_export_linkage := if p.os == .msvc && p.attr == 'live' && p.pref.is_so {
|
dll_export_linkage := if p.os == .msvc && p.attr == 'live' && p.pref.is_so {
|
||||||
'__declspec(dllexport) '
|
'__declspec(dllexport) '
|
||||||
} else {
|
} else {
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
if !p.is_vweb {
|
if !p.is_vweb {
|
||||||
p.cur_fn = f
|
p.cur_fn = f
|
||||||
}
|
}
|
||||||
// Generate `User_register()` instead of `register()`
|
// Generate `User_register()` instead of `register()`
|
||||||
// Internally it's still stored as "register" in type User
|
// Internally it's still stored as "register" in type User
|
||||||
mut fn_name_cgen := p.table.cgen_name(f)
|
mut fn_name_cgen := p.table.cgen_name(f)
|
||||||
// Start generation of the function body
|
// Start generation of the function body
|
||||||
|
@ -293,27 +293,27 @@ fn (p mut Parser) fn_decl() {
|
||||||
if p.pref.obfuscate {
|
if p.pref.obfuscate {
|
||||||
p.genln('; // $f.name')
|
p.genln('; // $f.name')
|
||||||
}
|
}
|
||||||
// Generate this function's body for all generic types
|
// Generate this function's body for all generic types
|
||||||
if is_generic {
|
if is_generic {
|
||||||
gen_types := p.table.fn_gen_types(f.name)
|
gen_types := p.table.fn_gen_types(f.name)
|
||||||
// Remember current scanner position, go back here for each type
|
// Remember current scanner position, go back here for each type
|
||||||
// TODO remove this once tokens are cached in `new_parser()`
|
// TODO remove this once tokens are cached in `new_parser()`
|
||||||
cur_pos := p.scanner.pos
|
cur_pos := p.scanner.pos
|
||||||
cur_tok := p.tok
|
cur_tok := p.tok
|
||||||
cur_lit := p.lit
|
cur_lit := p.lit
|
||||||
for gen_type in gen_types {
|
for gen_type in gen_types {
|
||||||
p.genln('$dll_export_linkage$typ ${fn_name_cgen}_$gen_type($str_args) {')
|
p.genln('$dll_export_linkage$typ ${fn_name_cgen}_$gen_type($str_args) {')
|
||||||
p.genln('// T start $p.pass ${p.strtok()}')
|
p.genln('// T start $p.pass ${p.strtok()}')
|
||||||
p.cur_gen_type = gen_type // TODO support more than T
|
p.cur_gen_type = gen_type // TODO support more than T
|
||||||
p.statements()
|
p.statements()
|
||||||
p.scanner.pos = cur_pos
|
p.scanner.pos = cur_pos
|
||||||
p.tok = cur_tok
|
p.tok = cur_tok
|
||||||
p.lit = cur_lit
|
p.lit = cur_lit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p.genln('$dll_export_linkage$typ $fn_name_cgen($str_args) {')
|
p.genln('$dll_export_linkage$typ $fn_name_cgen($str_args) {')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_fn_header {
|
if is_fn_header {
|
||||||
p.genln('$typ $fn_name_cgen($str_args);')
|
p.genln('$typ $fn_name_cgen($str_args);')
|
||||||
|
@ -329,11 +329,11 @@ fn (p mut Parser) fn_decl() {
|
||||||
// struct declaration later will modify it instead of creating a new one.
|
// struct declaration later will modify it instead of creating a new one.
|
||||||
if p.first_pass() && receiver_t.name == '' {
|
if p.first_pass() && receiver_t.name == '' {
|
||||||
// println('fn decl !!!!!!! REG PH $receiver_typ')
|
// println('fn decl !!!!!!! REG PH $receiver_typ')
|
||||||
p.table.register_type2(Type {
|
p.table.register_type2(Type {
|
||||||
name: receiver_typ.replace('*', '')
|
name: receiver_typ.replace('*', '')
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
is_placeholder: true
|
is_placeholder: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// f.idx = p.table.fn_cnt
|
// f.idx = p.table.fn_cnt
|
||||||
receiver_t.add_method(f)
|
receiver_t.add_method(f)
|
||||||
|
@ -343,8 +343,8 @@ fn (p mut Parser) fn_decl() {
|
||||||
p.table.register_fn(f)
|
p.table.register_fn(f)
|
||||||
}
|
}
|
||||||
if is_sig || p.first_pass() || is_live || is_fn_header || skip_main_in_test {
|
if is_sig || p.first_pass() || is_live || is_fn_header || skip_main_in_test {
|
||||||
// First pass? Skip the body for now
|
// First pass? Skip the body for now
|
||||||
// Look for generic calls.
|
// Look for generic calls.
|
||||||
if !is_sig && !is_fn_header {
|
if !is_sig && !is_fn_header {
|
||||||
mut opened_scopes := 0
|
mut opened_scopes := 0
|
||||||
mut closed_scopes := 0
|
mut closed_scopes := 0
|
||||||
|
@ -357,23 +357,23 @@ fn (p mut Parser) fn_decl() {
|
||||||
closed_scopes++
|
closed_scopes++
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
// find `foo<Bar>()` in function bodies and register generic types
|
// find `foo<Bar>()` in function bodies and register generic types
|
||||||
// TODO remove this once tokens are cached
|
// TODO remove this once tokens are cached
|
||||||
if p.tok == .gt && p.prev_tok == .name && p.prev_tok2 == .lt &&
|
if p.tok == .gt && p.prev_tok == .name && p.prev_tok2 == .lt &&
|
||||||
p.scanner.text[p.scanner.pos-1] != `T` {
|
p.scanner.text[p.scanner.pos-1] != `T` {
|
||||||
temp_scanner_pos = p.scanner.pos
|
temp_scanner_pos = p.scanner.pos
|
||||||
p.scanner.pos -= 3
|
p.scanner.pos -= 3
|
||||||
for p.scanner.pos > 0 && (is_name_char(p.scanner.text[p.scanner.pos]) ||
|
for p.scanner.pos > 0 && (is_name_char(p.scanner.text[p.scanner.pos]) ||
|
||||||
p.scanner.text[p.scanner.pos] == `.` ||
|
p.scanner.text[p.scanner.pos] == `.` ||
|
||||||
p.scanner.text[p.scanner.pos] == `<` ) {
|
p.scanner.text[p.scanner.pos] == `<` ) {
|
||||||
p.scanner.pos--
|
p.scanner.pos--
|
||||||
}
|
}
|
||||||
p.scanner.pos--
|
p.scanner.pos--
|
||||||
p.next()
|
p.next()
|
||||||
// Run the function in the firt pass to register the generic type
|
// Run the function in the firt pass to register the generic type
|
||||||
p.name_expr()
|
p.name_expr()
|
||||||
p.scanner.pos = temp_scanner_pos
|
p.scanner.pos = temp_scanner_pos
|
||||||
}
|
}
|
||||||
if p.tok.is_decl() && !(p.prev_tok == .dot && p.tok == .key_type) {
|
if p.tok.is_decl() && !(p.prev_tok == .dot && p.tok == .key_type) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -382,16 +382,16 @@ fn (p mut Parser) fn_decl() {
|
||||||
if p.tok == .lsbr {
|
if p.tok == .lsbr {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Live code reloading? Load all fns from .so
|
// Live code reloading? Load all fns from .so
|
||||||
if is_live && p.first_pass() && p.mod == 'main' {
|
if is_live && p.first_pass() && p.mod == 'main' {
|
||||||
//println('ADDING SO FN $fn_name_cgen')
|
//println('ADDING SO FN $fn_name_cgen')
|
||||||
p.cgen.so_fns << fn_name_cgen
|
p.cgen.so_fns << fn_name_cgen
|
||||||
fn_name_cgen = '(* $fn_name_cgen )'
|
fn_name_cgen = '(* $fn_name_cgen )'
|
||||||
}
|
}
|
||||||
// Function definition that goes to the top of the C file.
|
// Function definition that goes to the top of the C file.
|
||||||
mut fn_decl := '$dll_export_linkage$typ $fn_name_cgen($str_args)'
|
mut fn_decl := '$dll_export_linkage$typ $fn_name_cgen($str_args)'
|
||||||
if p.pref.obfuscate {
|
if p.pref.obfuscate {
|
||||||
fn_decl += '; // $f.name'
|
fn_decl += '; // $f.name'
|
||||||
|
@ -422,15 +422,15 @@ fn (p mut Parser) fn_decl() {
|
||||||
}
|
}
|
||||||
// We are in live code reload mode, call the .so loader in bg
|
// We are in live code reload mode, call the .so loader in bg
|
||||||
if p.pref.is_live {
|
if p.pref.is_live {
|
||||||
file_base := p.file_path.replace('.v', '')
|
file_base := p.file_path.replace('.v', '')
|
||||||
if p.os != .windows && p.os != .msvc {
|
if p.os != .windows && p.os != .msvc {
|
||||||
so_name := file_base + '.so'
|
so_name := file_base + '.so'
|
||||||
p.genln('
|
p.genln('
|
||||||
load_so("$so_name");
|
load_so("$so_name");
|
||||||
pthread_t _thread_so;
|
pthread_t _thread_so;
|
||||||
pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
|
pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
|
||||||
} else {
|
} else {
|
||||||
so_name := file_base + if p.os == .msvc {'.dll'} else {'.so'}
|
so_name := file_base + if p.os == .msvc {'.dll'} else {'.so'}
|
||||||
p.genln('
|
p.genln('
|
||||||
live_fn_mutex = CreateMutexA(0, 0, 0);
|
live_fn_mutex = CreateMutexA(0, 0, 0);
|
||||||
load_so("$so_name");
|
load_so("$so_name");
|
||||||
|
@ -454,20 +454,20 @@ _thread_so = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&reload_so, 0, 0, 0);
|
||||||
cgen_name := p.table.cgen_name(f)
|
cgen_name := p.table.cgen_name(f)
|
||||||
f.defer_text[f.scope_level] = ' ${cgen_name}_time += time__ticks() - _PROF_START;'
|
f.defer_text[f.scope_level] = ' ${cgen_name}_time += time__ticks() - _PROF_START;'
|
||||||
}
|
}
|
||||||
if is_generic {
|
if is_generic {
|
||||||
// Don't need to generate body for the actual generic definition
|
// Don't need to generate body for the actual generic definition
|
||||||
p.cgen.nogen = true
|
p.cgen.nogen = true
|
||||||
}
|
}
|
||||||
p.statements_no_rcbr()
|
p.statements_no_rcbr()
|
||||||
p.cgen.nogen = false
|
p.cgen.nogen = false
|
||||||
// Print counting result after all statements in main
|
// Print counting result after all statements in main
|
||||||
if p.pref.is_prof && f.name == 'main' {
|
if p.pref.is_prof && f.name == 'main' {
|
||||||
p.genln(p.print_prof_counters())
|
p.genln(p.print_prof_counters())
|
||||||
}
|
}
|
||||||
// Counting or not, always need to add defer before the end
|
// Counting or not, always need to add defer before the end
|
||||||
if !p.is_vweb {
|
if !p.is_vweb {
|
||||||
p.genln(f.defer_text[f.scope_level])
|
p.genln(f.defer_text[f.scope_level])
|
||||||
}
|
}
|
||||||
if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' {
|
if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' {
|
||||||
p.error('$f.name must return "$typ"')
|
p.error('$f.name must return "$typ"')
|
||||||
}
|
}
|
||||||
|
@ -485,16 +485,16 @@ _thread_so = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&reload_so, 0, 0, 0);
|
||||||
// Make sure all vars in this function are used (only in main for now)
|
// Make sure all vars in this function are used (only in main for now)
|
||||||
// if p.builtin_mod || p.mod == 'os' ||p.mod=='http'{
|
// if p.builtin_mod || p.mod == 'os' ||p.mod=='http'{
|
||||||
if p.mod != 'main' {
|
if p.mod != 'main' {
|
||||||
if !is_generic {
|
if !is_generic {
|
||||||
p.genln('}')
|
p.genln('}')
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.check_unused_variables()
|
p.check_unused_variables()
|
||||||
p.cur_fn = EmptyFn
|
p.cur_fn = EmptyFn
|
||||||
if !is_generic {
|
if !is_generic {
|
||||||
p.genln('}')
|
p.genln('}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) check_unused_variables() {
|
fn (p mut Parser) check_unused_variables() {
|
||||||
|
@ -508,7 +508,7 @@ fn (p mut Parser) check_unused_variables() {
|
||||||
}
|
}
|
||||||
if !var.is_changed && var.is_mut && !p.pref.is_repl && !var.is_arg && !p.pref.translated && var.name != '_' {
|
if !var.is_changed && var.is_mut && !p.pref.is_repl && !var.is_arg && !p.pref.translated && var.name != '_' {
|
||||||
p.scanner.line_nr = var.line_nr - 1
|
p.scanner.line_nr = var.line_nr - 1
|
||||||
p.error('`$var.name` is declared as mutable, but it was never changed')
|
p.error('`$var.name` is declared as mutable, but it was never changed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,7 +524,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
|
||||||
// Normal function => just its name, method => TYPE_FN.name
|
// Normal function => just its name, method => TYPE_FN.name
|
||||||
mut fn_name := f.name
|
mut fn_name := f.name
|
||||||
if f.is_method {
|
if f.is_method {
|
||||||
fn_name = receiver_type.replace('*', '') + '_' + f.name
|
fn_name = receiver_type.replace('*', '') + '_' + f.name
|
||||||
//fn_name = '${receiver_type}_${f.name}'
|
//fn_name = '${receiver_type}_${f.name}'
|
||||||
}
|
}
|
||||||
// Generate tmp struct with args
|
// Generate tmp struct with args
|
||||||
|
@ -592,39 +592,39 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type string) {
|
fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type string) {
|
||||||
if !f.is_public && !f.is_c && !p.pref.is_test && !f.is_interface && f.mod != p.mod {
|
if !f.is_public && !f.is_c && !p.pref.is_test && !f.is_interface && f.mod != p.mod {
|
||||||
p.error('function `$f.name` is private')
|
p.error('function `$f.name` is private')
|
||||||
}
|
}
|
||||||
p.calling_c = f.is_c
|
p.calling_c = f.is_c
|
||||||
if f.is_c && !p.builtin_mod {
|
if f.is_c && !p.builtin_mod {
|
||||||
if f.name == 'free' {
|
if f.name == 'free' {
|
||||||
p.error('use `free()` instead of `C.free()`')
|
p.error('use `free()` instead of `C.free()`')
|
||||||
} else if f.name == 'malloc' {
|
} else if f.name == 'malloc' {
|
||||||
p.error('use `malloc()` instead of `C.malloc()`')
|
p.error('use `malloc()` instead of `C.malloc()`')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut cgen_name := p.table.cgen_name(f)
|
mut cgen_name := p.table.cgen_name(f)
|
||||||
p.next()
|
p.next()
|
||||||
mut gen_type := ''
|
mut gen_type := ''
|
||||||
if p.tok == .lt {
|
if p.tok == .lt {
|
||||||
p.check(.lt)
|
p.check(.lt)
|
||||||
gen_type = p.check_name()
|
gen_type = p.check_name()
|
||||||
// run<T> => run_App
|
// run<T> => run_App
|
||||||
if gen_type == 'T' && p.cur_gen_type != '' {
|
if gen_type == 'T' && p.cur_gen_type != '' {
|
||||||
gen_type = p.cur_gen_type
|
gen_type = p.cur_gen_type
|
||||||
}
|
}
|
||||||
// `foo<Bar>()`
|
// `foo<Bar>()`
|
||||||
// If we are in the first pass, we need to add `Bar` type to the generic function `foo`,
|
// If we are in the first pass, we need to add `Bar` type to the generic function `foo`,
|
||||||
// so that generic `foo`s body can be generated for each type in the second pass.
|
// so that generic `foo`s body can be generated for each type in the second pass.
|
||||||
if p.first_pass() {
|
if p.first_pass() {
|
||||||
println('registering $gen_type in $f.name fname=$f.name')
|
println('registering $gen_type in $f.name fname=$f.name')
|
||||||
p.table.register_generic_fn_type(f.name, gen_type)
|
p.table.register_generic_fn_type(f.name, gen_type)
|
||||||
// Function bodies are skipped in the first passed, we only need to register the generic type here.
|
// Function bodies are skipped in the first passed, we only need to register the generic type here.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cgen_name += '_' + gen_type
|
cgen_name += '_' + gen_type
|
||||||
p.check(.gt)
|
p.check(.gt)
|
||||||
}
|
}
|
||||||
// if p.pref.is_prof {
|
// if p.pref.is_prof {
|
||||||
// p.cur_fn.called_fns << cgen_name
|
// p.cur_fn.called_fns << cgen_name
|
||||||
// }
|
// }
|
||||||
|
@ -642,10 +642,10 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
|
||||||
if receiver.is_mut && !p.expr_var.is_mut {
|
if receiver.is_mut && !p.expr_var.is_mut {
|
||||||
println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut')
|
println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut')
|
||||||
p.error('`$p.expr_var.name` is immutable, declare it with `mut`')
|
p.error('`$p.expr_var.name` is immutable, declare it with `mut`')
|
||||||
}
|
}
|
||||||
if !p.expr_var.is_changed {
|
if !p.expr_var.is_changed {
|
||||||
p.cur_fn.mark_var_changed(p.expr_var)
|
p.cur_fn.mark_var_changed(p.expr_var)
|
||||||
}
|
}
|
||||||
// if receiver is key_mut or a ref (&), generate & for the first arg
|
// if receiver is key_mut or a ref (&), generate & for the first arg
|
||||||
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) {
|
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) {
|
||||||
method_call += '& /* ? */'
|
method_call += '& /* ? */'
|
||||||
|
@ -664,7 +664,7 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
|
||||||
}
|
}
|
||||||
p.cgen.set_placeholder(method_ph, '$cast $method_call')
|
p.cgen.set_placeholder(method_ph, '$cast $method_call')
|
||||||
}
|
}
|
||||||
// foo<Bar>()
|
// foo<Bar>()
|
||||||
p.fn_call_args(mut f)
|
p.fn_call_args(mut f)
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
p.calling_c = false
|
p.calling_c = false
|
||||||
|
@ -675,14 +675,14 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
|
||||||
// return an updated Fn object with args[] field set
|
// return an updated Fn object with args[] field set
|
||||||
fn (p mut Parser) fn_args(f mut Fn) {
|
fn (p mut Parser) fn_args(f mut Fn) {
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
defer { p.check(.rpar) }
|
defer { p.check(.rpar) }
|
||||||
if f.is_interface {
|
if f.is_interface {
|
||||||
int_arg := Var {
|
int_arg := Var {
|
||||||
typ: f.receiver_typ
|
typ: f.receiver_typ
|
||||||
}
|
}
|
||||||
f.args << int_arg
|
f.args << int_arg
|
||||||
}
|
}
|
||||||
// `(int, string, int)`
|
// `(int, string, int)`
|
||||||
// Just register fn arg types
|
// Just register fn arg types
|
||||||
types_only := p.tok == .mul || (p.peek() == .comma && p.table.known_type(p.lit)) || p.peek() == .rpar// (int, string)
|
types_only := p.tok == .mul || (p.peek() == .comma && p.table.known_type(p.lit)) || p.peek() == .rpar// (int, string)
|
||||||
if types_only {
|
if types_only {
|
||||||
|
@ -719,19 +719,19 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||||
}
|
}
|
||||||
mut typ := p.get_type()
|
mut typ := p.get_type()
|
||||||
if is_mut && is_primitive_type(typ) {
|
if is_mut && is_primitive_type(typ) {
|
||||||
p.error('mutable arguments are only allowed for arrays, maps, and structs.' +
|
p.error('mutable arguments are only allowed for arrays, maps, and structs.' +
|
||||||
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`')
|
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`')
|
||||||
}
|
}
|
||||||
for name in names {
|
for name in names {
|
||||||
if !p.first_pass() && !p.table.known_type(typ) {
|
if !p.first_pass() && !p.table.known_type(typ) {
|
||||||
p.error('fn_args: unknown type $typ')
|
p.error('fn_args: unknown type $typ')
|
||||||
}
|
}
|
||||||
if is_mut {
|
if is_mut {
|
||||||
typ += '*'
|
typ += '*'
|
||||||
}
|
}
|
||||||
v := Var {
|
v := Var {
|
||||||
name: name
|
name: name
|
||||||
typ: typ
|
typ: typ
|
||||||
is_arg: true
|
is_arg: true
|
||||||
is_mut: is_mut
|
is_mut: is_mut
|
||||||
ptr: is_mut
|
ptr: is_mut
|
||||||
|
@ -752,7 +752,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// foo *(1, 2, 3, mut bar)*
|
// foo *(1, 2, 3, mut bar)*
|
||||||
fn (p mut Parser) fn_call_args(f mut Fn) *Fn {
|
fn (p mut Parser) fn_call_args(f mut Fn) *Fn {
|
||||||
// p.gen('(')
|
// p.gen('(')
|
||||||
// println('fn_call_args() name=$f.name args.len=$f.args.len')
|
// println('fn_call_args() name=$f.name args.len=$f.args.len')
|
||||||
|
@ -795,72 +795,72 @@ fn (p mut Parser) fn_call_args(f mut Fn) *Fn {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ph := p.cgen.add_placeholder()
|
ph := p.cgen.add_placeholder()
|
||||||
// `)` here means that not enough args were provided
|
// `)` here means that not enough args were provided
|
||||||
if p.tok == .rpar {
|
if p.tok == .rpar {
|
||||||
str_args := f.str_args(p.table)// TODO this is C args
|
str_args := f.str_args(p.table)// TODO this is C args
|
||||||
p.error('not enough arguments in call to `$f.name ($str_args)`')
|
p.error('not enough arguments in call to `$f.name ($str_args)`')
|
||||||
}
|
}
|
||||||
// If `arg` is mutable, the caller needs to provide `mut`:
|
// If `arg` is mutable, the caller needs to provide `mut`:
|
||||||
// `mut numbers := [1,2,3]; reverse(mut numbers);`
|
// `mut numbers := [1,2,3]; reverse(mut numbers);`
|
||||||
if arg.is_mut {
|
if arg.is_mut {
|
||||||
if p.tok != .key_mut && p.tok == .name {
|
if p.tok != .key_mut && p.tok == .name {
|
||||||
mut dots_example := 'mut $p.lit'
|
mut dots_example := 'mut $p.lit'
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
dots_example = '.., ' + dots_example
|
dots_example = '.., ' + dots_example
|
||||||
}
|
}
|
||||||
if i < f.args.len - 1 {
|
if i < f.args.len - 1 {
|
||||||
dots_example = dots_example + ',..'
|
dots_example = dots_example + ',..'
|
||||||
}
|
}
|
||||||
p.error('`$arg.name` is a mutable argument, you need to provide `mut`: `$f.name($dots_example)`')
|
p.error('`$arg.name` is a mutable argument, you need to provide `mut`: `$f.name($dots_example)`')
|
||||||
}
|
}
|
||||||
if p.peek() != .name {
|
if p.peek() != .name {
|
||||||
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
||||||
}
|
}
|
||||||
p.check(.key_mut)
|
p.check(.key_mut)
|
||||||
var_name := p.lit
|
var_name := p.lit
|
||||||
v := p.cur_fn.find_var(var_name)
|
v := p.cur_fn.find_var(var_name)
|
||||||
if v.name == '' {
|
if v.name == '' {
|
||||||
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
||||||
}
|
}
|
||||||
if !v.is_changed {
|
if !v.is_changed {
|
||||||
p.cur_fn.mark_var_changed(v)
|
p.cur_fn.mark_var_changed(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expected_type = arg.typ
|
p.expected_type = arg.typ
|
||||||
typ := p.bool_expression()
|
typ := p.bool_expression()
|
||||||
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
||||||
// function calls. `println(777)` => `printf("%d\n", 777)`
|
// function calls. `println(777)` => `printf("%d\n", 777)`
|
||||||
// (If we don't check for void, then V will compile `println(func())`)
|
// (If we don't check for void, then V will compile `println(func())`)
|
||||||
if i == 0 && f.name == 'println' && typ != 'string' && typ != 'void' {
|
if i == 0 && f.name == 'println' && typ != 'string' && typ != 'void' {
|
||||||
T := p.table.find_type(typ)
|
T := p.table.find_type(typ)
|
||||||
$if !windows {
|
$if !windows {
|
||||||
fmt := p.typ_to_fmt(typ, 0)
|
fmt := p.typ_to_fmt(typ, 0)
|
||||||
if fmt != '' {
|
if fmt != '' {
|
||||||
p.cgen.resetln(p.cgen.cur_line.replace('println (', '/*opt*/printf ("' + fmt + '\\n", '))
|
p.cgen.resetln(p.cgen.cur_line.replace('println (', '/*opt*/printf ("' + fmt + '\\n", '))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if typ.ends_with('*') {
|
if typ.ends_with('*') {
|
||||||
p.cgen.set_placeholder(ph, 'ptr_str(')
|
p.cgen.set_placeholder(ph, 'ptr_str(')
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Make sure this type has a `str()` method
|
// Make sure this type has a `str()` method
|
||||||
if !T.has_method('str') {
|
if !T.has_method('str') {
|
||||||
// Arrays have automatic `str()` methods
|
// Arrays have automatic `str()` methods
|
||||||
if T.name.starts_with('array_') {
|
if T.name.starts_with('array_') {
|
||||||
p.gen_array_str(mut T)
|
p.gen_array_str(mut T)
|
||||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
error_msg := ('`$typ` needs to have method `str() string` to be printable')
|
error_msg := ('`$typ` needs to have method `str() string` to be printable')
|
||||||
if T.fields.len > 0 {
|
if T.fields.len > 0 {
|
||||||
mut index := p.cgen.cur_line.len - 1
|
mut index := p.cgen.cur_line.len - 1
|
||||||
for index > 0 && p.cgen.cur_line[index] != ` ` { index-- }
|
for index > 0 && p.cgen.cur_line[index] != ` ` { index-- }
|
||||||
name := p.cgen.cur_line.right(index + 1)
|
name := p.cgen.cur_line.right(index + 1)
|
||||||
if name == '}' {
|
if name == '}' {
|
||||||
p.error(error_msg)
|
p.error(error_msg)
|
||||||
}
|
}
|
||||||
p.cgen.resetln(p.cgen.cur_line.left(index))
|
p.cgen.resetln(p.cgen.cur_line.left(index))
|
||||||
p.scanner.create_type_string(T, name)
|
p.scanner.create_type_string(T, name)
|
||||||
|
@ -868,7 +868,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) *Fn {
|
||||||
p.next()
|
p.next()
|
||||||
return p.fn_call_args(mut f)
|
return p.fn_call_args(mut f)
|
||||||
}
|
}
|
||||||
p.error(error_msg)
|
p.error(error_msg)
|
||||||
}
|
}
|
||||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
|
@ -893,18 +893,18 @@ fn (p mut Parser) fn_call_args(f mut Fn) *Fn {
|
||||||
// TODO ptr hacks. DOOM hacks, fix please.
|
// TODO ptr hacks. DOOM hacks, fix please.
|
||||||
if !got.contains('*') && expected.contains('*') && got != 'voidptr' {
|
if !got.contains('*') && expected.contains('*') && got != 'voidptr' {
|
||||||
// Special case for mutable arrays. We can't `&` function results,
|
// Special case for mutable arrays. We can't `&` function results,
|
||||||
// have to use `(array[]){ expr }` hack.
|
// have to use `(array[]){ expr }` hack.
|
||||||
if expected.starts_with('array_') && expected.ends_with('*') {
|
if expected.starts_with('array_') && expected.ends_with('*') {
|
||||||
p.cgen.set_placeholder(ph, '& /*111*/ (array[]){')
|
p.cgen.set_placeholder(ph, '& /*111*/ (array[]){')
|
||||||
p.gen('} ')
|
p.gen('} ')
|
||||||
}
|
}
|
||||||
// println('\ne:"$expected" got:"$got"')
|
// println('\ne:"$expected" got:"$got"')
|
||||||
else if ! (expected == 'void*' && got == 'int') &&
|
else if ! (expected == 'void*' && got == 'int') &&
|
||||||
! (expected == 'byte*' && got.contains(']byte')) &&
|
! (expected == 'byte*' && got.contains(']byte')) &&
|
||||||
! (expected == 'byte*' && got == 'string') &&
|
! (expected == 'byte*' && got == 'string') &&
|
||||||
//! (expected == 'void*' && got == 'array_int') {
|
//! (expected == 'void*' && got == 'array_int') {
|
||||||
! (expected == 'byte*' && got == 'byteptr') {
|
! (expected == 'byte*' && got == 'byteptr') {
|
||||||
p.cgen.set_placeholder(ph, '& /*112 EXP:"$expected" GOT:"$got" */')
|
p.cgen.set_placeholder(ph, '& /*112 EXP:"$expected" GOT:"$got" */')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,23 +57,23 @@ fn (p mut Parser) gen_json_for_type(typ Type) {
|
||||||
p.table.register_fn(enc_fn)
|
p.table.register_fn(enc_fn)
|
||||||
// Code gen decoder
|
// Code gen decoder
|
||||||
dec += '
|
dec += '
|
||||||
//$t $dec_fn.name(cJSON* root) {
|
//$t $dec_fn.name(cJSON* root) {
|
||||||
Option $dec_fn.name(cJSON* root, $t* res) {
|
Option $dec_fn.name(cJSON* root, $t* res) {
|
||||||
// $t res;
|
// $t res;
|
||||||
if (!root) {
|
if (!root) {
|
||||||
const char *error_ptr = cJSON_GetErrorPtr();
|
const char *error_ptr = cJSON_GetErrorPtr();
|
||||||
if (error_ptr != NULL) {
|
if (error_ptr != NULL) {
|
||||||
fprintf(stderr, "Error in decode() for $t error_ptr=: %%s\\n", error_ptr);
|
fprintf(stderr, "Error in decode() for $t error_ptr=: %%s\\n", error_ptr);
|
||||||
// printf("\\nbad js=%%s\\n", js.str);
|
// printf("\\nbad js=%%s\\n", js.str);
|
||||||
return v_error(tos2(error_ptr));
|
return v_error(tos2(error_ptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
// Code gen encoder
|
// Code gen encoder
|
||||||
enc += '
|
enc += '
|
||||||
cJSON* $enc_fn.name($t val) {
|
cJSON* $enc_fn.name($t val) {
|
||||||
cJSON *o = cJSON_CreateObject();
|
cJSON *o = cJSON_CreateObject();
|
||||||
string res = tos2("");
|
string res = tos2("");
|
||||||
'
|
'
|
||||||
// Handle arrays
|
// Handle arrays
|
||||||
if t.starts_with('array_') {
|
if t.starts_with('array_') {
|
||||||
|
@ -144,7 +144,7 @@ fn (p mut Parser) decode_array(array_type string) string {
|
||||||
const cJSON *jsval = NULL;
|
const cJSON *jsval = NULL;
|
||||||
cJSON_ArrayForEach(jsval, root)
|
cJSON_ArrayForEach(jsval, root)
|
||||||
{
|
{
|
||||||
$s
|
$s
|
||||||
array__push(res, &val);
|
array__push(res, &val);
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
|
@ -167,7 +167,7 @@ fn (p &Parser) encode_array(array_type string) string {
|
||||||
o = cJSON_CreateArray();
|
o = cJSON_CreateArray();
|
||||||
for (int i = 0; i < val.len; i++){
|
for (int i = 0; i < val.len; i++){
|
||||||
cJSON_AddItemToArray(o, $fn_name( (($typ*)val.data)[i] ));
|
cJSON_AddItemToArray(o, $fn_name( (($typ*)val.data)[i] ));
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
490
compiler/main.v
490
compiler/main.v
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@ mut:
|
||||||
fmt_out strings.Builder
|
fmt_out strings.Builder
|
||||||
fmt_indent int
|
fmt_indent int
|
||||||
fmt_line_empty bool
|
fmt_line_empty bool
|
||||||
prev_tok Token
|
prev_tok Token
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_scanner(file_path string) *Scanner {
|
fn new_scanner(file_path string) *Scanner {
|
||||||
|
@ -207,7 +207,7 @@ fn (s Scanner) has_gone_over_line_end() bool {
|
||||||
|
|
||||||
fn (s mut Scanner) skip_whitespace() {
|
fn (s mut Scanner) skip_whitespace() {
|
||||||
for s.pos < s.text.len && s.text[s.pos].is_white() {
|
for s.pos < s.text.len && s.text[s.pos].is_white() {
|
||||||
// Count \r\n as one line
|
// Count \r\n as one line
|
||||||
if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) {
|
if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) {
|
||||||
s.line_nr++
|
s.line_nr++
|
||||||
}
|
}
|
||||||
|
@ -216,10 +216,10 @@ fn (s mut Scanner) skip_whitespace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s mut Scanner) scan() ScanRes {
|
fn (s mut Scanner) scan() ScanRes {
|
||||||
if s.line_comment != '' {
|
if s.line_comment != '' {
|
||||||
//s.fgenln('// LOL "$s.line_comment"')
|
//s.fgenln('// LOL "$s.line_comment"')
|
||||||
//s.line_comment = ''
|
//s.line_comment = ''
|
||||||
}
|
}
|
||||||
if s.started {
|
if s.started {
|
||||||
s.pos++
|
s.pos++
|
||||||
}
|
}
|
||||||
|
@ -388,11 +388,11 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
case `,`:
|
case `,`:
|
||||||
return scan_res(.comma, '')
|
return scan_res(.comma, '')
|
||||||
case `@`:
|
case `@`:
|
||||||
s.pos++
|
s.pos++
|
||||||
name := s.ident_name()
|
name := s.ident_name()
|
||||||
if !is_key(name) {
|
if !is_key(name) {
|
||||||
s.error('@ must be used before keywords (e.g. `@type string`)')
|
s.error('@ must be used before keywords (e.g. `@type string`)')
|
||||||
}
|
}
|
||||||
return scan_res(.name, name)
|
return scan_res(.name, name)
|
||||||
case `\r`:
|
case `\r`:
|
||||||
if nextc == `\n` {
|
if nextc == `\n` {
|
||||||
|
@ -477,7 +477,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
else if nextc == `>` {
|
else if nextc == `>` {
|
||||||
s.pos++
|
s.pos++
|
||||||
return scan_res(.arrow, '')
|
return scan_res(.arrow, '')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return scan_res(.assign, '')
|
return scan_res(.assign, '')
|
||||||
}
|
}
|
||||||
|
@ -515,7 +515,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
s.line_comment = s.text.substr(start + 1, s.pos)
|
s.line_comment = s.text.substr(start + 1, s.pos)
|
||||||
s.line_comment = s.line_comment.trim_space()
|
s.line_comment = s.line_comment.trim_space()
|
||||||
s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"')
|
s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"')
|
||||||
// Skip the comment (return the next token)
|
// Skip the comment (return the next token)
|
||||||
return s.scan()
|
return s.scan()
|
||||||
}
|
}
|
||||||
// Multiline comments
|
// Multiline comments
|
||||||
|
@ -553,13 +553,13 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
$if windows {
|
$if windows {
|
||||||
if c == `\0` {
|
if c == `\0` {
|
||||||
return scan_res(.eof, '')
|
return scan_res(.eof, '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut msg := 'invalid character `${c.str()}`'
|
mut msg := 'invalid character `${c.str()}`'
|
||||||
if c == `"` {
|
if c == `"` {
|
||||||
msg += ', use \' to denote strings'
|
msg += ', use \' to denote strings'
|
||||||
}
|
}
|
||||||
s.error(msg)
|
s.error(msg)
|
||||||
return scan_res(.eof, '')
|
return scan_res(.eof, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,17 +797,17 @@ fn contains_capital(s string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPRequest bad
|
// HTTPRequest bad
|
||||||
// HttpRequest good
|
// HttpRequest good
|
||||||
fn good_type_name(s string) bool {
|
fn good_type_name(s string) bool {
|
||||||
if s.len < 4 {
|
if s.len < 4 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for i in 2 .. s.len {
|
for i in 2 .. s.len {
|
||||||
if s[i].is_capital() && s[i-1].is_capital() && s[i-2].is_capital() {
|
if s[i].is_capital() && s[i-1].is_capital() && s[i-2].is_capital() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
180
compiler/table.v
180
compiler/table.v
|
@ -4,15 +4,15 @@
|
||||||
|
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
struct Table {
|
struct Table {
|
||||||
mut:
|
mut:
|
||||||
types []Type
|
types []Type
|
||||||
consts []Var
|
consts []Var
|
||||||
fns map[string]Fn
|
fns map[string]Fn
|
||||||
generic_fns []GenTable //map[string]GenTable // generic_fns['listen_and_serve'] == ['Blog', 'Forum']
|
generic_fns []GenTable //map[string]GenTable // generic_fns['listen_and_serve'] == ['Blog', 'Forum']
|
||||||
obf_ids map[string]int // obf_ids['myfunction'] == 23
|
obf_ids map[string]int // obf_ids['myfunction'] == 23
|
||||||
modules []string // List of all modules registered by the application
|
modules []string // List of all modules registered by the application
|
||||||
imports []string // List of all imports
|
imports []string // List of all imports
|
||||||
|
@ -23,9 +23,9 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GenTable {
|
struct GenTable {
|
||||||
fn_name string
|
fn_name string
|
||||||
types []string
|
types []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holds import information scoped to the parsed file
|
// Holds import information scoped to the parsed file
|
||||||
struct FileImportTable {
|
struct FileImportTable {
|
||||||
|
@ -36,8 +36,8 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AccessMod {
|
enum AccessMod {
|
||||||
private // private immutable
|
private // private immutable
|
||||||
private_mut // private mutable
|
private_mut // private mutable
|
||||||
public // public immutable (readonly)
|
public // public immutable (readonly)
|
||||||
public_mut // public, but mutable only in this module
|
public_mut // public, but mutable only in this module
|
||||||
public_mut_mut // public and mutable both inside and outside (not recommended to use, that's why it's so verbose)
|
public_mut_mut // public and mutable both inside and outside (not recommended to use, that's why it's so verbose)
|
||||||
|
@ -54,13 +54,13 @@ mut:
|
||||||
is_c bool // C.FI.le
|
is_c bool // C.FI.le
|
||||||
is_interface bool
|
is_interface bool
|
||||||
is_enum bool
|
is_enum bool
|
||||||
enum_vals []string
|
enum_vals []string
|
||||||
gen_types []string
|
gen_types []string
|
||||||
// This field is used for types that are not defined yet but are known to exist.
|
// This field is used for types that are not defined yet but are known to exist.
|
||||||
// It allows having things like `fn (f Foo) bar()` before `Foo` is defined.
|
// It allows having things like `fn (f Foo) bar()` before `Foo` is defined.
|
||||||
// This information is needed in the first pass.
|
// This information is needed in the first pass.
|
||||||
is_placeholder bool
|
is_placeholder bool
|
||||||
gen_str bool // needs `.str()` method generation
|
gen_str bool // needs `.str()` method generation
|
||||||
}
|
}
|
||||||
|
|
||||||
// For debugging types
|
// For debugging types
|
||||||
|
@ -109,12 +109,12 @@ fn (f Fn) str() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) debug_fns() string {
|
fn (t &Table) debug_fns() string {
|
||||||
mut s := strings.new_builder(1000)
|
mut s := strings.new_builder(1000)
|
||||||
for _, f in t.fns {
|
for _, f in t.fns {
|
||||||
s.writeln(f.name)
|
s.writeln(f.name)
|
||||||
}
|
}
|
||||||
return s.str()
|
return s.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn (types array_Type) print_to_file(f string) {
|
// fn (types array_Type) print_to_file(f string) {
|
||||||
// }
|
// }
|
||||||
|
@ -124,23 +124,23 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
fn is_number_type(typ string) bool {
|
fn is_number_type(typ string) bool {
|
||||||
return typ in number_types
|
return typ in number_types
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_float_type(typ string) bool {
|
fn is_float_type(typ string) bool {
|
||||||
return typ in float_types
|
return typ in float_types
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_primitive_type(typ string) bool {
|
fn is_primitive_type(typ string) bool {
|
||||||
return is_number_type(typ) || typ == 'string'
|
return is_number_type(typ) || typ == 'string'
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
fns: map[string]Fn
|
||||||
//generic_fns: map[string]GenTable{}
|
//generic_fns: map[string]GenTable{}
|
||||||
generic_fns: []GenTable
|
generic_fns: []GenTable
|
||||||
obfuscate: obfuscate
|
obfuscate: obfuscate
|
||||||
file_imports: []FileImportTable
|
file_imports: []FileImportTable
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ fn (t mut Table) register_const(name, typ, mod string, is_imported bool) {
|
||||||
typ: typ
|
typ: typ
|
||||||
is_const: true
|
is_const: true
|
||||||
is_import_const: is_imported
|
is_import_const: is_imported
|
||||||
mod: mod
|
mod: mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,17 +234,17 @@ fn (p mut Parser) register_global(name, typ string) {
|
||||||
typ: typ
|
typ: typ
|
||||||
is_const: true
|
is_const: true
|
||||||
is_global: true
|
is_global: true
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
is_mut: true
|
is_mut: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t mut Table) register_fn(new_fn Fn) {
|
fn (t mut Table) register_fn(new_fn Fn) {
|
||||||
t.fns[new_fn.name] = new_fn
|
t.fns[new_fn.name] = new_fn
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (table &Table) known_type(typ_ string) bool {
|
fn (table &Table) known_type(typ_ string) bool {
|
||||||
mut typ := typ_
|
mut typ := typ_
|
||||||
// 'byte*' => look up 'byte', but don't mess up fns
|
// 'byte*' => look up 'byte', but don't mess up fns
|
||||||
if typ.ends_with('*') && !typ.contains(' ') {
|
if typ.ends_with('*') && !typ.contains(' ') {
|
||||||
typ = typ.left(typ.len - 1)
|
typ = typ.left(typ.len - 1)
|
||||||
|
@ -258,16 +258,16 @@ fn (table &Table) known_type(typ_ string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) find_fn(name string) Fn {
|
fn (t &Table) find_fn(name string) Fn {
|
||||||
f := t.fns[name]
|
f := t.fns[name]
|
||||||
if !isnil(f.name.str) {
|
if !isnil(f.name.str) {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
return Fn{}
|
return Fn{}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) known_fn(name string) bool {
|
fn (t &Table) known_fn(name string) bool {
|
||||||
f := t.find_fn(name)
|
f := t.find_fn(name)
|
||||||
return f.name != ''
|
return f.name != ''
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) known_const(name string) bool {
|
fn (t &Table) known_const(name string) bool {
|
||||||
|
@ -318,10 +318,10 @@ if parent == 'array' {
|
||||||
mod = 'builtin'
|
mod = 'builtin'
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
t.types << Type {
|
t.types << Type {
|
||||||
name: typ
|
name: typ
|
||||||
parent: parent
|
parent: parent
|
||||||
//mod: mod
|
//mod: mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +357,7 @@ fn (t &Type) has_field(name string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Type) has_enum_val(name string) bool {
|
fn (t &Type) has_enum_val(name string) bool {
|
||||||
return name in t.enum_vals
|
return name in t.enum_vals
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Type) find_field(name string) Var {
|
fn (t &Type) find_field(name string) Var {
|
||||||
|
@ -425,7 +425,7 @@ fn (t &Type) find_method(name string) Fn {
|
||||||
return Fn{}
|
return Fn{}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fn (t mut Type) add_gen_type(type_name string) {
|
fn (t mut Type) add_gen_type(type_name string) {
|
||||||
// println('add_gen_type($s)')
|
// println('add_gen_type($s)')
|
||||||
if t.gen_types.contains(type_name) {
|
if t.gen_types.contains(type_name) {
|
||||||
|
@ -433,7 +433,7 @@ fn (t mut Type) add_gen_type(type_name string) {
|
||||||
}
|
}
|
||||||
t.gen_types << type_name
|
t.gen_types << type_name
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn (p &Parser) find_type(name string) &Type {
|
fn (p &Parser) find_type(name string) &Type {
|
||||||
typ := p.table.find_type(name)
|
typ := p.table.find_type(name)
|
||||||
|
@ -444,7 +444,7 @@ fn (p &Parser) find_type(name string) &Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) find_type(name_ string) *Type {
|
fn (t &Table) find_type(name_ string) *Type {
|
||||||
mut name := name_
|
mut name := name_
|
||||||
if name.ends_with('*') && !name.contains(' ') {
|
if name.ends_with('*') && !name.contains(' ') {
|
||||||
name = name.left(name.len - 1)
|
name = name.left(name.len - 1)
|
||||||
}
|
}
|
||||||
|
@ -458,8 +458,8 @@ fn (t &Table) find_type(name_ string) *Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool {
|
fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool {
|
||||||
mut got := got_
|
mut got := got_
|
||||||
mut expected := expected_
|
mut expected := expected_
|
||||||
p.log('check types got="$got" exp="$expected" ')
|
p.log('check types got="$got" exp="$expected" ')
|
||||||
if p.pref.translated {
|
if p.pref.translated {
|
||||||
return true
|
return true
|
||||||
|
@ -505,13 +505,13 @@ fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool {
|
||||||
}
|
}
|
||||||
if got=='byte*' && expected=='byteptr' {
|
if got=='byte*' && expected=='byteptr' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if got=='int' && expected=='byte*' {
|
if got=='int' && expected=='byte*' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
//if got=='int' && expected=='voidptr*' {
|
//if got=='int' && expected=='voidptr*' {
|
||||||
//return true
|
//return true
|
||||||
//}
|
//}
|
||||||
// byteptr += int
|
// byteptr += int
|
||||||
if got=='int' && expected=='byteptr' {
|
if got=='int' && expected=='byteptr' {
|
||||||
return true
|
return true
|
||||||
|
@ -593,7 +593,7 @@ fn type_default(typ string) string {
|
||||||
if typ.ends_with('*') {
|
if typ.ends_with('*') {
|
||||||
return '0'
|
return '0'
|
||||||
}
|
}
|
||||||
// User struct defined in another module.
|
// User struct defined in another module.
|
||||||
if typ.contains('__') {
|
if typ.contains('__') {
|
||||||
return 'STRUCT_DEFAULT_VALUE'
|
return 'STRUCT_DEFAULT_VALUE'
|
||||||
}
|
}
|
||||||
|
@ -617,7 +617,7 @@ fn type_default(typ string) string {
|
||||||
case 'byteptr': return '0'
|
case 'byteptr': return '0'
|
||||||
case 'voidptr': return '0'
|
case 'voidptr': return '0'
|
||||||
}
|
}
|
||||||
return 'STRUCT_DEFAULT_VALUE'
|
return 'STRUCT_DEFAULT_VALUE'
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO PERF O(n)
|
// TODO PERF O(n)
|
||||||
|
@ -632,7 +632,7 @@ 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 _, f in t.fns {
|
||||||
if f.name == 'main' {
|
if f.name == 'main' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -713,51 +713,51 @@ fn (table &Table) cgen_name_type_pair(name, typ string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid_int_const(val, typ string) bool {
|
fn is_valid_int_const(val, typ string) bool {
|
||||||
x := val.int()
|
x := val.int()
|
||||||
switch typ {
|
switch typ {
|
||||||
case 'byte', 'u8': return 0 <= x && x <= math.MaxU8
|
case 'byte', 'u8': return 0 <= x && x <= math.MaxU8
|
||||||
case 'u16': return 0 <= x && x <= math.MaxU16
|
case 'u16': return 0 <= x && x <= math.MaxU16
|
||||||
//case 'u32': return 0 <= x && x <= math.MaxU32
|
//case 'u32': return 0 <= x && x <= math.MaxU32
|
||||||
//case 'u64': return 0 <= x && x <= math.MaxU64
|
//case 'u64': return 0 <= x && x <= math.MaxU64
|
||||||
//////////////
|
//////////////
|
||||||
case 'i8': return math.MinI8 <= x && x <= math.MaxI8
|
case 'i8': return math.MinI8 <= x && x <= math.MaxI8
|
||||||
case 'i16': return math.MinI16 <= x && x <= math.MaxI16
|
case 'i16': return math.MinI16 <= x && x <= math.MaxI16
|
||||||
case 'int', 'i32': return math.MinI32 <= x && x <= math.MaxI32
|
case 'int', 'i32': return math.MinI32 <= x && x <= math.MaxI32
|
||||||
//case 'i64':
|
//case 'i64':
|
||||||
//x64 := val.i64()
|
//x64 := val.i64()
|
||||||
//return i64(-(1<<63)) <= x64 && x64 <= i64((1<<63)-1)
|
//return i64(-(1<<63)) <= x64 && x64 <= i64((1<<63)-1)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t mut Table) register_generic_fn(fn_name string) {
|
fn (t mut Table) register_generic_fn(fn_name string) {
|
||||||
t.generic_fns << GenTable{fn_name, []string}
|
t.generic_fns << GenTable{fn_name, []string}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t mut Table) fn_gen_types(fn_name string) []string {
|
fn (t mut Table) fn_gen_types(fn_name string) []string {
|
||||||
for _, f in t.generic_fns {
|
for _, f in t.generic_fns {
|
||||||
if f.fn_name == fn_name {
|
if f.fn_name == fn_name {
|
||||||
return f.types
|
return f.types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic('function $fn_name not found')
|
panic('function $fn_name not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
// `foo<Bar>()`
|
// `foo<Bar>()`
|
||||||
// fn_name == 'foo'
|
// fn_name == 'foo'
|
||||||
// typ == 'Bar'
|
// typ == 'Bar'
|
||||||
fn (t mut Table) register_generic_fn_type(fn_name, typ string) {
|
fn (t mut Table) register_generic_fn_type(fn_name, typ string) {
|
||||||
for i, f in t.generic_fns {
|
for i, f in t.generic_fns {
|
||||||
if f.fn_name == fn_name {
|
if f.fn_name == fn_name {
|
||||||
t.generic_fns[i].types << typ
|
t.generic_fns[i].types << typ
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) typ_to_fmt(typ string, level int) string {
|
fn (p mut Parser) typ_to_fmt(typ string, level int) string {
|
||||||
t := p.table.find_type(typ)
|
t := p.table.find_type(typ)
|
||||||
if t.is_enum {
|
if t.is_enum {
|
||||||
return '%d'
|
return '%d'
|
||||||
}
|
}
|
||||||
switch typ {
|
switch typ {
|
||||||
|
@ -775,12 +775,12 @@ fn (p mut Parser) typ_to_fmt(typ string, level int) string {
|
||||||
case 'void': p.error('cannot interpolate this value')
|
case 'void': p.error('cannot interpolate this value')
|
||||||
default:
|
default:
|
||||||
if typ.ends_with('*') {
|
if typ.ends_with('*') {
|
||||||
return '%p'
|
return '%p'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if t.parent != '' && level == 0 {
|
||||||
|
return p.typ_to_fmt(t.parent, level+1)
|
||||||
}
|
}
|
||||||
if t.parent != '' && level == 0 {
|
|
||||||
return p.typ_to_fmt(t.parent, level+1)
|
|
||||||
}
|
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,7 +818,7 @@ fn (table &Table) qualify_module(mod string, file_path string) string {
|
||||||
fn new_file_import_table(file_path string) *FileImportTable {
|
fn new_file_import_table(file_path string) *FileImportTable {
|
||||||
return &FileImportTable{
|
return &FileImportTable{
|
||||||
file_path: file_path
|
file_path: file_path
|
||||||
imports: map[string]string
|
imports: map[string]string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,7 +831,7 @@ fn (fit mut FileImportTable) register_import(mod string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (fit mut FileImportTable) register_alias(alias string, mod string) {
|
fn (fit mut FileImportTable) register_alias(alias string, mod string) {
|
||||||
if alias in fit.imports {
|
if alias in fit.imports {
|
||||||
panic('cannot import $mod as $alias: import name $alias already in use in "${fit.file_path}".')
|
panic('cannot import $mod as $alias: import name $alias already in use in "${fit.file_path}".')
|
||||||
}
|
}
|
||||||
if mod.contains('.internal.') {
|
if mod.contains('.internal.') {
|
||||||
|
@ -850,14 +850,14 @@ fn (fit mut FileImportTable) register_alias(alias string, mod string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (fit &FileImportTable) known_alias(alias string) bool {
|
fn (fit &FileImportTable) known_alias(alias string) bool {
|
||||||
return alias in fit.imports
|
return alias in fit.imports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (fit &FileImportTable) is_aliased(mod string) bool {
|
fn (fit &FileImportTable) is_aliased(mod string) bool {
|
||||||
for _, val in fit.imports {
|
for _, val in fit.imports {
|
||||||
if val == mod {
|
if val == mod {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,35 +6,35 @@ module main
|
||||||
|
|
||||||
enum Token {
|
enum Token {
|
||||||
eof
|
eof
|
||||||
name // user
|
name // user
|
||||||
number // 123
|
number // 123
|
||||||
str // 'foo'
|
str // 'foo'
|
||||||
str_inter // 'name=$user.name'
|
str_inter // 'name=$user.name'
|
||||||
chartoken // `A`
|
chartoken // `A`
|
||||||
plus
|
plus
|
||||||
minus
|
minus
|
||||||
mul
|
mul
|
||||||
div
|
div
|
||||||
mod
|
mod
|
||||||
xor // ^
|
xor // ^
|
||||||
pipe // |
|
pipe // |
|
||||||
inc // ++
|
inc // ++
|
||||||
dec // --
|
dec // --
|
||||||
and // &&
|
and // &&
|
||||||
logical_or
|
logical_or
|
||||||
not
|
not
|
||||||
bit_not
|
bit_not
|
||||||
question
|
question
|
||||||
comma
|
comma
|
||||||
semicolon
|
semicolon
|
||||||
colon
|
colon
|
||||||
arrow // =>
|
arrow // =>
|
||||||
amp
|
amp
|
||||||
hash
|
hash
|
||||||
dollar
|
dollar
|
||||||
left_shift
|
left_shift
|
||||||
righ_shift
|
righ_shift
|
||||||
//at // @
|
//at // @
|
||||||
// = := += -=
|
// = := += -=
|
||||||
assign
|
assign
|
||||||
decl_assign
|
decl_assign
|
||||||
|
@ -63,10 +63,10 @@ enum Token {
|
||||||
ge
|
ge
|
||||||
le
|
le
|
||||||
// comments
|
// comments
|
||||||
//line_com
|
//line_com
|
||||||
//mline_com
|
//mline_com
|
||||||
nl
|
nl
|
||||||
dot
|
dot
|
||||||
dotdot
|
dotdot
|
||||||
// keywords
|
// keywords
|
||||||
keyword_beg
|
keyword_beg
|
||||||
|
@ -77,8 +77,8 @@ enum Token {
|
||||||
key_case
|
key_case
|
||||||
key_const
|
key_const
|
||||||
key_continue
|
key_continue
|
||||||
key_default
|
key_default
|
||||||
key_defer
|
key_defer
|
||||||
key_else
|
key_else
|
||||||
key_embed
|
key_embed
|
||||||
key_enum
|
key_enum
|
||||||
|
@ -87,26 +87,26 @@ enum Token {
|
||||||
func
|
func
|
||||||
key_global
|
key_global
|
||||||
key_go
|
key_go
|
||||||
key_goto
|
key_goto
|
||||||
key_if
|
key_if
|
||||||
key_import
|
key_import
|
||||||
key_import_const
|
key_import_const
|
||||||
key_in
|
key_in
|
||||||
key_interface
|
key_interface
|
||||||
key_match
|
key_match
|
||||||
key_module
|
key_module
|
||||||
key_mut
|
key_mut
|
||||||
key_return
|
key_return
|
||||||
key_select
|
key_select
|
||||||
key_sizeof
|
key_sizeof
|
||||||
key_struct
|
key_struct
|
||||||
key_switch
|
key_switch
|
||||||
key_true
|
key_true
|
||||||
key_type
|
key_type
|
||||||
//typeof
|
//typeof
|
||||||
key_orelse
|
key_orelse
|
||||||
key_union
|
key_union
|
||||||
key_pub
|
key_pub
|
||||||
key_static
|
key_static
|
||||||
keyword_end
|
keyword_end
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ enum Token {
|
||||||
// build_keys genereates a map with keywords' string values:
|
// build_keys genereates a map with keywords' string values:
|
||||||
// Keywords['return'] == .key_return
|
// Keywords['return'] == .key_return
|
||||||
fn build_keys() map[string]int {
|
fn build_keys() map[string]int {
|
||||||
mut res := map[string]int
|
mut res := map[string]int
|
||||||
for t := int(Token.keyword_beg) + 1; t < int(Token.keyword_end); t++ {
|
for t := int(Token.keyword_beg) + 1; t < int(Token.keyword_end); t++ {
|
||||||
key := TokenStr[t]
|
key := TokenStr[t]
|
||||||
res[key] = int(t)
|
res[key] = int(t)
|
||||||
|
@ -122,7 +122,7 @@ fn build_keys() map[string]int {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove once we have `enum Token { name('name') if('if') ... }`
|
// TODO remove once we have `enum Token { name('name') if('if') ... }`
|
||||||
fn build_token_str() []string {
|
fn build_token_str() []string {
|
||||||
mut s := [''; NrTokens]
|
mut s := [''; NrTokens]
|
||||||
s[Token.keyword_beg] = ''
|
s[Token.keyword_beg] = ''
|
||||||
|
@ -246,9 +246,9 @@ fn (t Token) str() string {
|
||||||
|
|
||||||
fn (t Token) is_decl() bool {
|
fn (t Token) is_decl() bool {
|
||||||
// TODO i
|
// TODO i
|
||||||
//return t in [.key_enum, .key_interface, .func, .typ, .key_const,
|
//return t in [.key_enum, .key_interface, .func, .typ, .key_const,
|
||||||
//.key_import_const, .key_struct, .key_pub, .eof]
|
//.key_import_const, .key_struct, .key_pub, .eof]
|
||||||
return t == .key_enum || t == .key_interface || t == .func ||
|
return t == .key_enum || t == .key_interface || t == .func ||
|
||||||
t == .key_struct || t == .key_type ||
|
t == .key_struct || t == .key_type ||
|
||||||
t == .key_const || t == .key_import_const || t == .key_pub || t == .eof
|
t == .key_const || t == .key_import_const || t == .key_pub || t == .eof
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ fn (t Token) is_decl() bool {
|
||||||
const (
|
const (
|
||||||
AssignTokens = [
|
AssignTokens = [
|
||||||
Token.assign, Token.plus_assign, Token.minus_assign,
|
Token.assign, Token.plus_assign, Token.minus_assign,
|
||||||
Token.mult_assign, Token.div_assign, Token.xor_assign,
|
Token.mult_assign, Token.div_assign, Token.xor_assign,
|
||||||
Token.mod_assign,
|
Token.mod_assign,
|
||||||
Token.or_assign, Token.and_assign, Token.righ_shift_assign,
|
Token.or_assign, Token.and_assign, Token.righ_shift_assign,
|
||||||
Token.left_shift_assign
|
Token.left_shift_assign
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
// fmt helpers
|
// fmt helpers
|
||||||
fn (scanner mut Scanner) fgen(s_ string) {
|
fn (scanner mut Scanner) fgen(s_ string) {
|
||||||
mut s := s_
|
mut s := s_
|
||||||
if scanner.fmt_line_empty {
|
if scanner.fmt_line_empty {
|
||||||
s = strings.repeat(`\t`, scanner.fmt_indent) + s
|
s = strings.repeat(`\t`, scanner.fmt_indent) + s
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ fn (scanner mut Scanner) fgen(s_ string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (scanner mut Scanner) fgenln(s_ string) {
|
fn (scanner mut Scanner) fgenln(s_ string) {
|
||||||
mut s := s_
|
mut s := s_
|
||||||
if scanner.fmt_line_empty {
|
if scanner.fmt_line_empty {
|
||||||
s = strings.repeat(`\t`, scanner.fmt_indent) + s
|
s = strings.repeat(`\t`, scanner.fmt_indent) + s
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ module builtin
|
||||||
|
|
||||||
struct string {
|
struct string {
|
||||||
//mut:
|
//mut:
|
||||||
//hash_cache int
|
//hash_cache int
|
||||||
pub:
|
pub:
|
||||||
str byteptr
|
str byteptr
|
||||||
len int
|
len int
|
||||||
|
@ -22,10 +22,10 @@ pub:
|
||||||
// For C strings only
|
// For C strings only
|
||||||
fn C.strlen(s byteptr) int
|
fn C.strlen(s byteptr) int
|
||||||
|
|
||||||
fn todo() { }
|
fn todo() { }
|
||||||
|
|
||||||
// Converts a C string to a V string.
|
// Converts a C string to a V string.
|
||||||
// String data is reused, not copied.
|
// String data is reused, not copied.
|
||||||
pub fn tos(s byteptr, len int) string {
|
pub fn tos(s byteptr, len int) string {
|
||||||
// This should never happen.
|
// This should never happen.
|
||||||
if isnil(s) {
|
if isnil(s) {
|
||||||
|
@ -44,8 +44,8 @@ pub fn tos_clone(s byteptr) string {
|
||||||
return tos2(s).clone()
|
return tos2(s).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
fn tos2(s byteptr) string {
|
||||||
if isnil(s) {
|
if isnil(s) {
|
||||||
panic('tos2: nil string')
|
panic('tos2: nil string')
|
||||||
|
@ -67,12 +67,12 @@ pub fn (a string) clone() string {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pub fn (s string) cstr() byteptr {
|
pub fn (s string) cstr() byteptr {
|
||||||
clone := s.clone()
|
clone := s.clone()
|
||||||
return clone.str
|
return clone.str
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn (s string) replace(rep, with string) string {
|
pub fn (s string) replace(rep, with string) string {
|
||||||
if s.len == 0 || rep.len == 0 {
|
if s.len == 0 || rep.len == 0 {
|
||||||
|
@ -285,7 +285,7 @@ pub fn (s string) split_single(delim byte) []string {
|
||||||
}
|
}
|
||||||
val := s.substr(start, i)
|
val := s.substr(start, i)
|
||||||
if val.len > 0 {
|
if val.len > 0 {
|
||||||
res << val
|
res << val
|
||||||
}
|
}
|
||||||
start = i + 1
|
start = i + 1
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ pub fn (s string) right(n int) string {
|
||||||
return s.substr(n, s.len)
|
return s.substr(n, s.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// substr
|
// substr
|
||||||
pub fn (s string) substr(start, end int) string {
|
pub fn (s string) substr(start, end int) string {
|
||||||
if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
|
if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
|
||||||
panic('substr($start, $end) out of bounds (len=$s.len)')
|
panic('substr($start, $end) out of bounds (len=$s.len)')
|
||||||
|
@ -345,12 +345,12 @@ pub fn (s string) substr(start, end int) string {
|
||||||
}
|
}
|
||||||
res.str[len] = `\0`
|
res.str[len] = `\0`
|
||||||
|
|
||||||
/*
|
/*
|
||||||
res := string {
|
res := string {
|
||||||
str: s.str + start
|
str: s.str + start
|
||||||
len: len
|
len: len
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,16 +531,16 @@ pub fn (ar []int) contains(val int) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pub fn (a []string) to_c() voidptr {
|
pub fn (a []string) to_c() voidptr {
|
||||||
mut res := malloc(sizeof(byteptr) * a.len)
|
mut res := malloc(sizeof(byteptr) * a.len)
|
||||||
for i := 0; i < a.len; i++ {
|
for i := 0; i < a.len; i++ {
|
||||||
val := a[i]
|
val := a[i]
|
||||||
res[i] = val.str
|
res[i] = val.str
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn is_space(c byte) bool {
|
fn is_space(c byte) bool {
|
||||||
return C.isspace(c)
|
return C.isspace(c)
|
||||||
|
@ -563,8 +563,8 @@ pub fn (s string) trim_space() string {
|
||||||
end--
|
end--
|
||||||
}
|
}
|
||||||
if i > end + 1 {
|
if i > end + 1 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
res := s.substr(i, end + 1)
|
res := s.substr(i, end + 1)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -599,12 +599,12 @@ pub fn (s string) trim_left(cutset string) string {
|
||||||
|
|
||||||
pub fn (s string) trim_right(cutset string) string {
|
pub fn (s string) trim_right(cutset string) string {
|
||||||
if s.len == 0 {
|
if s.len == 0 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
mut pos := s.len - 1
|
mut pos := s.len - 1
|
||||||
for s[pos] == cutset[0] {
|
for s[pos] == cutset[0] {
|
||||||
pos--
|
pos--
|
||||||
}
|
}
|
||||||
return s.left(pos+1)
|
return s.left(pos+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,14 +743,14 @@ pub fn (s string) free() {
|
||||||
free(s.str)
|
free(s.str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fn (arr []string) free() {
|
fn (arr []string) free() {
|
||||||
for s in arr {
|
for s in arr {
|
||||||
s.free()
|
s.free()
|
||||||
}
|
}
|
||||||
C.free(arr.data)
|
C.free(arr.data)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// all_before('23:34:45.234', '.') == '23:34:45'
|
// all_before('23:34:45.234', '.') == '23:34:45'
|
||||||
pub fn (s string) all_before(dot string) string {
|
pub fn (s string) all_before(dot string) string {
|
||||||
|
@ -848,14 +848,14 @@ pub fn (c byte) is_white() bool {
|
||||||
|
|
||||||
|
|
||||||
pub fn (s string) hash() int {
|
pub fn (s string) hash() int {
|
||||||
//mut h := s.hash_cache
|
//mut h := s.hash_cache
|
||||||
mut h := 0
|
mut h := 0
|
||||||
if h == 0 && s.len > 0 {
|
if h == 0 && s.len > 0 {
|
||||||
for c in s {
|
for c in s {
|
||||||
h = h * 31 + int(c)
|
h = h * 31 + int(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s string) bytes() []byte {
|
pub fn (s string) bytes() []byte {
|
||||||
|
|
Loading…
Reference in New Issue