fmt: remove trailing spaces

pull/1639/head
Alexander Medvednikov 2019-08-17 22:19:37 +03:00
parent 8a1324c141
commit fe2d2bd2a3
9 changed files with 1049 additions and 1049 deletions

View File

@ -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" */')
} }
} }
} }

View File

@ -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] ));
} }
' '
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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

View File

@ -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
} }

View File

@ -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 {