fmt: remove trailing spaces
parent
8a1324c141
commit
fe2d2bd2a3
284
compiler/fn.v
284
compiler/fn.v
|
@ -4,7 +4,7 @@
|
|||
|
||||
module main
|
||||
|
||||
import strings
|
||||
import strings
|
||||
|
||||
const (
|
||||
MaxLocalVars = 50
|
||||
|
@ -30,7 +30,7 @@ mut:
|
|||
returns_error bool
|
||||
is_decl bool // type myfn fn(int, int)
|
||||
defer_text []string
|
||||
//gen_types []string
|
||||
//gen_types []string
|
||||
}
|
||||
|
||||
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.
|
||||
fn (p mut Parser) fn_decl() {
|
||||
p.fgen('fn ')
|
||||
//defer { p.fgenln('\n') }
|
||||
is_pub := p.tok == .key_pub
|
||||
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 {
|
||||
println('INFO: run `v -live program.v` if you want to use [live] functions')
|
||||
}
|
||||
//defer { p.fgenln('\n') }
|
||||
is_pub := p.tok == .key_pub
|
||||
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 {
|
||||
println('INFO: run `v -live program.v` if you want to use [live] functions')
|
||||
}
|
||||
if is_pub {
|
||||
p.next()
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ fn (p mut Parser) fn_decl() {
|
|||
is_mut := p.tok == .key_mut
|
||||
is_amp := p.tok == .amp
|
||||
if is_mut || is_amp {
|
||||
p.check_space(p.tok)
|
||||
p.check_space(p.tok)
|
||||
}
|
||||
receiver_typ = p.get_type()
|
||||
T := p.table.find_type(receiver_typ)
|
||||
|
@ -159,7 +159,7 @@ fn (p mut Parser) fn_decl() {
|
|||
receiver_typ += '*'
|
||||
}
|
||||
p.check(.rpar)
|
||||
p.fspace()
|
||||
p.fspace()
|
||||
receiver := Var {
|
||||
name: receiver_name
|
||||
is_arg: true
|
||||
|
@ -180,7 +180,7 @@ fn (p mut Parser) fn_decl() {
|
|||
f.name = p.check_name()
|
||||
}
|
||||
// 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
|
||||
// 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))
|
||||
|
@ -228,12 +228,12 @@ fn (p mut Parser) fn_decl() {
|
|||
p.error('only `T` is allowed as a generic type for now')
|
||||
}
|
||||
p.check(.gt)
|
||||
if p.first_pass() {
|
||||
p.table.register_generic_fn(f.name)
|
||||
} else {
|
||||
//gen_types := p.table.fn_gen_types(f.name)
|
||||
//println(gen_types)
|
||||
}
|
||||
if p.first_pass() {
|
||||
p.table.register_generic_fn(f.name)
|
||||
} else {
|
||||
//gen_types := p.table.fn_gen_types(f.name)
|
||||
//println(gen_types)
|
||||
}
|
||||
}
|
||||
// Args (...)
|
||||
p.fn_args(mut f)
|
||||
|
@ -252,7 +252,7 @@ fn (p mut Parser) fn_decl() {
|
|||
typ = p.get_type()
|
||||
}
|
||||
// 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 {
|
||||
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 {
|
||||
'__declspec(dllexport) '
|
||||
} else {
|
||||
''
|
||||
}
|
||||
if !p.is_vweb {
|
||||
''
|
||||
}
|
||||
if !p.is_vweb {
|
||||
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
|
||||
mut fn_name_cgen := p.table.cgen_name(f)
|
||||
// Start generation of the function body
|
||||
|
@ -293,27 +293,27 @@ fn (p mut Parser) fn_decl() {
|
|||
if p.pref.obfuscate {
|
||||
p.genln('; // $f.name')
|
||||
}
|
||||
// Generate this function's body for all generic types
|
||||
if is_generic {
|
||||
gen_types := p.table.fn_gen_types(f.name)
|
||||
// Generate this function's body for all generic types
|
||||
if is_generic {
|
||||
gen_types := p.table.fn_gen_types(f.name)
|
||||
// Remember current scanner position, go back here for each type
|
||||
// TODO remove this once tokens are cached in `new_parser()`
|
||||
cur_pos := p.scanner.pos
|
||||
cur_tok := p.tok
|
||||
cur_lit := p.lit
|
||||
// TODO remove this once tokens are cached in `new_parser()`
|
||||
cur_pos := p.scanner.pos
|
||||
cur_tok := p.tok
|
||||
cur_lit := p.lit
|
||||
for gen_type in gen_types {
|
||||
p.genln('$dll_export_linkage$typ ${fn_name_cgen}_$gen_type($str_args) {')
|
||||
p.genln('// T start $p.pass ${p.strtok()}')
|
||||
p.cur_gen_type = gen_type // TODO support more than T
|
||||
p.genln('$dll_export_linkage$typ ${fn_name_cgen}_$gen_type($str_args) {')
|
||||
p.genln('// T start $p.pass ${p.strtok()}')
|
||||
p.cur_gen_type = gen_type // TODO support more than T
|
||||
p.statements()
|
||||
p.scanner.pos = cur_pos
|
||||
p.tok = cur_tok
|
||||
p.lit = cur_lit
|
||||
}
|
||||
}
|
||||
else {
|
||||
p.scanner.pos = cur_pos
|
||||
p.tok = cur_tok
|
||||
p.lit = cur_lit
|
||||
}
|
||||
}
|
||||
else {
|
||||
p.genln('$dll_export_linkage$typ $fn_name_cgen($str_args) {')
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_fn_header {
|
||||
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.
|
||||
if p.first_pass() && receiver_t.name == '' {
|
||||
// println('fn decl !!!!!!! REG PH $receiver_typ')
|
||||
p.table.register_type2(Type {
|
||||
p.table.register_type2(Type {
|
||||
name: receiver_typ.replace('*', '')
|
||||
mod: p.mod
|
||||
is_placeholder: true
|
||||
})
|
||||
})
|
||||
}
|
||||
// f.idx = p.table.fn_cnt
|
||||
receiver_t.add_method(f)
|
||||
|
@ -343,8 +343,8 @@ fn (p mut Parser) fn_decl() {
|
|||
p.table.register_fn(f)
|
||||
}
|
||||
if is_sig || p.first_pass() || is_live || is_fn_header || skip_main_in_test {
|
||||
// First pass? Skip the body for now
|
||||
// Look for generic calls.
|
||||
// First pass? Skip the body for now
|
||||
// Look for generic calls.
|
||||
if !is_sig && !is_fn_header {
|
||||
mut opened_scopes := 0
|
||||
mut closed_scopes := 0
|
||||
|
@ -357,23 +357,23 @@ fn (p mut Parser) fn_decl() {
|
|||
closed_scopes++
|
||||
}
|
||||
p.next()
|
||||
// find `foo<Bar>()` in function bodies and register generic types
|
||||
// TODO remove this once tokens are cached
|
||||
// find `foo<Bar>()` in function bodies and register generic types
|
||||
// TODO remove this once tokens are cached
|
||||
if p.tok == .gt && p.prev_tok == .name && p.prev_tok2 == .lt &&
|
||||
p.scanner.text[p.scanner.pos-1] != `T` {
|
||||
temp_scanner_pos = p.scanner.pos
|
||||
p.scanner.pos -= 3
|
||||
for p.scanner.pos > 0 && (is_name_char(p.scanner.text[p.scanner.pos]) ||
|
||||
p.scanner.pos -= 3
|
||||
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.pos--
|
||||
}
|
||||
p.scanner.pos--
|
||||
p.next()
|
||||
// Run the function in the firt pass to register the generic type
|
||||
p.name_expr()
|
||||
p.scanner.text[p.scanner.pos] == `<` ) {
|
||||
p.scanner.pos--
|
||||
}
|
||||
p.scanner.pos--
|
||||
p.next()
|
||||
// Run the function in the firt pass to register the generic type
|
||||
p.name_expr()
|
||||
p.scanner.pos = temp_scanner_pos
|
||||
}
|
||||
}
|
||||
if p.tok.is_decl() && !(p.prev_tok == .dot && p.tok == .key_type) {
|
||||
break
|
||||
}
|
||||
|
@ -382,16 +382,16 @@ fn (p mut Parser) fn_decl() {
|
|||
if p.tok == .lsbr {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Live code reloading? Load all fns from .so
|
||||
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
|
||||
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)'
|
||||
if p.pref.obfuscate {
|
||||
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
|
||||
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 {
|
||||
so_name := file_base + '.so'
|
||||
p.genln('
|
||||
load_so("$so_name");
|
||||
p.genln('
|
||||
load_so("$so_name");
|
||||
pthread_t _thread_so;
|
||||
pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
|
||||
} 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('
|
||||
live_fn_mutex = CreateMutexA(0, 0, 0);
|
||||
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)
|
||||
f.defer_text[f.scope_level] = ' ${cgen_name}_time += time__ticks() - _PROF_START;'
|
||||
}
|
||||
if is_generic {
|
||||
// Don't need to generate body for the actual generic definition
|
||||
p.cgen.nogen = true
|
||||
}
|
||||
if is_generic {
|
||||
// Don't need to generate body for the actual generic definition
|
||||
p.cgen.nogen = true
|
||||
}
|
||||
p.statements_no_rcbr()
|
||||
p.cgen.nogen = false
|
||||
p.cgen.nogen = false
|
||||
// Print counting result after all statements in main
|
||||
if p.pref.is_prof && f.name == 'main' {
|
||||
p.genln(p.print_prof_counters())
|
||||
}
|
||||
// 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])
|
||||
}
|
||||
}
|
||||
if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' {
|
||||
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)
|
||||
// if p.builtin_mod || p.mod == 'os' ||p.mod=='http'{
|
||||
if p.mod != 'main' {
|
||||
if !is_generic {
|
||||
if !is_generic {
|
||||
p.genln('}')
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
p.check_unused_variables()
|
||||
p.cur_fn = EmptyFn
|
||||
if !is_generic {
|
||||
if !is_generic {
|
||||
p.genln('}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 != '_' {
|
||||
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
|
||||
mut fn_name := f.name
|
||||
if f.is_method {
|
||||
fn_name = receiver_type.replace('*', '') + '_' + f.name
|
||||
fn_name = receiver_type.replace('*', '') + '_' + f.name
|
||||
//fn_name = '${receiver_type}_${f.name}'
|
||||
}
|
||||
// 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) {
|
||||
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.calling_c = f.is_c
|
||||
if f.is_c && !p.builtin_mod {
|
||||
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' {
|
||||
p.error('use `malloc()` instead of `C.malloc()`')
|
||||
}
|
||||
}
|
||||
p.error('use `malloc()` instead of `C.malloc()`')
|
||||
}
|
||||
}
|
||||
mut cgen_name := p.table.cgen_name(f)
|
||||
p.next()
|
||||
mut gen_type := ''
|
||||
mut gen_type := ''
|
||||
if p.tok == .lt {
|
||||
p.check(.lt)
|
||||
gen_type = p.check_name()
|
||||
// run<T> => run_App
|
||||
gen_type = p.check_name()
|
||||
// run<T> => run_App
|
||||
if gen_type == 'T' && p.cur_gen_type != '' {
|
||||
gen_type = p.cur_gen_type
|
||||
}
|
||||
// `foo<Bar>()`
|
||||
// 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.
|
||||
gen_type = p.cur_gen_type
|
||||
}
|
||||
// `foo<Bar>()`
|
||||
// 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.
|
||||
if p.first_pass() {
|
||||
println('registering $gen_type in $f.name fname=$f.name')
|
||||
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.
|
||||
return
|
||||
}
|
||||
cgen_name += '_' + gen_type
|
||||
println('registering $gen_type in $f.name fname=$f.name')
|
||||
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.
|
||||
return
|
||||
}
|
||||
cgen_name += '_' + gen_type
|
||||
p.check(.gt)
|
||||
}
|
||||
}
|
||||
// if p.pref.is_prof {
|
||||
// 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 {
|
||||
println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut')
|
||||
p.error('`$p.expr_var.name` is immutable, declare it with `mut`')
|
||||
}
|
||||
}
|
||||
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.ref || (receiver.is_mut && !receiver_type.contains('*')) {
|
||||
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')
|
||||
}
|
||||
// foo<Bar>()
|
||||
// foo<Bar>()
|
||||
p.fn_call_args(mut f)
|
||||
p.gen(')')
|
||||
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
|
||||
fn (p mut Parser) fn_args(f mut Fn) {
|
||||
p.check(.lpar)
|
||||
defer { p.check(.rpar) }
|
||||
defer { p.check(.rpar) }
|
||||
if f.is_interface {
|
||||
int_arg := Var {
|
||||
typ: f.receiver_typ
|
||||
}
|
||||
f.args << int_arg
|
||||
}
|
||||
// `(int, string, int)`
|
||||
// `(int, string, int)`
|
||||
// Just register fn arg types
|
||||
types_only := p.tok == .mul || (p.peek() == .comma && p.table.known_type(p.lit)) || p.peek() == .rpar// (int, string)
|
||||
if types_only {
|
||||
|
@ -719,19 +719,19 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
|||
}
|
||||
mut typ := p.get_type()
|
||||
if is_mut && is_primitive_type(typ) {
|
||||
p.error('mutable arguments are only allowed for arrays, maps, and structs.' +
|
||||
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`')
|
||||
}
|
||||
p.error('mutable arguments are only allowed for arrays, maps, and structs.' +
|
||||
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`')
|
||||
}
|
||||
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')
|
||||
}
|
||||
if is_mut {
|
||||
if is_mut {
|
||||
typ += '*'
|
||||
}
|
||||
v := Var {
|
||||
name: name
|
||||
typ: typ
|
||||
typ: typ
|
||||
is_arg: true
|
||||
is_mut: 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 {
|
||||
// p.gen('(')
|
||||
// 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
|
||||
}
|
||||
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 {
|
||||
str_args := f.str_args(p.table)// TODO this is C 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);`
|
||||
if arg.is_mut {
|
||||
if p.tok != .key_mut && p.tok == .name {
|
||||
mut dots_example := 'mut $p.lit'
|
||||
mut dots_example := 'mut $p.lit'
|
||||
if i > 0 {
|
||||
dots_example = '.., ' + dots_example
|
||||
}
|
||||
dots_example = '.., ' + dots_example
|
||||
}
|
||||
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)`')
|
||||
}
|
||||
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.check(.key_mut)
|
||||
var_name := p.lit
|
||||
v := p.cur_fn.find_var(var_name)
|
||||
if v.name == '' {
|
||||
var_name := p.lit
|
||||
v := p.cur_fn.find_var(var_name)
|
||||
if v.name == '' {
|
||||
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
||||
}
|
||||
}
|
||||
if !v.is_changed {
|
||||
p.cur_fn.mark_var_changed(v)
|
||||
}
|
||||
}
|
||||
p.expected_type = arg.typ
|
||||
p.cur_fn.mark_var_changed(v)
|
||||
}
|
||||
}
|
||||
p.expected_type = arg.typ
|
||||
typ := p.bool_expression()
|
||||
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
||||
// function calls. `println(777)` => `printf("%d\n", 777)`
|
||||
// (If we don't check for void, then V will compile `println(func())`)
|
||||
// function calls. `println(777)` => `printf("%d\n", 777)`
|
||||
// (If we don't check for void, then V will compile `println(func())`)
|
||||
if i == 0 && f.name == 'println' && typ != 'string' && typ != 'void' {
|
||||
T := p.table.find_type(typ)
|
||||
$if !windows {
|
||||
fmt := p.typ_to_fmt(typ, 0)
|
||||
if fmt != '' {
|
||||
p.cgen.resetln(p.cgen.cur_line.replace('println (', '/*opt*/printf ("' + fmt + '\\n", '))
|
||||
continue
|
||||
continue
|
||||
}
|
||||
}
|
||||
if typ.ends_with('*') {
|
||||
p.cgen.set_placeholder(ph, 'ptr_str(')
|
||||
p.gen(')')
|
||||
continue
|
||||
continue
|
||||
}
|
||||
// Make sure this type has a `str()` method
|
||||
if !T.has_method('str') {
|
||||
// Arrays have automatic `str()` methods
|
||||
// Arrays have automatic `str()` methods
|
||||
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.gen(')')
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
error_msg := ('`$typ` needs to have method `str() string` to be printable')
|
||||
if T.fields.len > 0 {
|
||||
mut index := p.cgen.cur_line.len - 1
|
||||
for index > 0 && p.cgen.cur_line[index] != ` ` { index-- }
|
||||
name := p.cgen.cur_line.right(index + 1)
|
||||
if name == '}' {
|
||||
p.error(error_msg)
|
||||
p.error(error_msg)
|
||||
}
|
||||
p.cgen.resetln(p.cgen.cur_line.left(index))
|
||||
p.scanner.create_type_string(T, name)
|
||||
|
@ -868,7 +868,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) *Fn {
|
|||
p.next()
|
||||
return p.fn_call_args(mut f)
|
||||
}
|
||||
p.error(error_msg)
|
||||
p.error(error_msg)
|
||||
}
|
||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||
p.gen(')')
|
||||
|
@ -893,18 +893,18 @@ fn (p mut Parser) fn_call_args(f mut Fn) *Fn {
|
|||
// TODO ptr hacks. DOOM hacks, fix please.
|
||||
if !got.contains('*') && expected.contains('*') && got != 'voidptr' {
|
||||
// Special case for mutable arrays. We can't `&` function results,
|
||||
// have to use `(array[]){ expr }` hack.
|
||||
if expected.starts_with('array_') && expected.ends_with('*') {
|
||||
p.cgen.set_placeholder(ph, '& /*111*/ (array[]){')
|
||||
p.gen('} ')
|
||||
}
|
||||
// have to use `(array[]){ expr }` hack.
|
||||
if expected.starts_with('array_') && expected.ends_with('*') {
|
||||
p.cgen.set_placeholder(ph, '& /*111*/ (array[]){')
|
||||
p.gen('} ')
|
||||
}
|
||||
// println('\ne:"$expected" got:"$got"')
|
||||
else if ! (expected == 'void*' && got == 'int') &&
|
||||
! (expected == 'byte*' && got.contains(']byte')) &&
|
||||
! (expected == 'byte*' && got == 'string') &&
|
||||
//! (expected == 'void*' && got == 'array_int') {
|
||||
! (expected == 'byte*' && got == 'byteptr') {
|
||||
p.cgen.set_placeholder(ph, '& /*112 EXP:"$expected" GOT:"$got" */')
|
||||
//! (expected == 'void*' && got == 'array_int') {
|
||||
! (expected == 'byte*' && got == 'byteptr') {
|
||||
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)
|
||||
// Code gen decoder
|
||||
dec += '
|
||||
//$t $dec_fn.name(cJSON* root) {
|
||||
Option $dec_fn.name(cJSON* root, $t* res) {
|
||||
// $t res;
|
||||
//$t $dec_fn.name(cJSON* root) {
|
||||
Option $dec_fn.name(cJSON* root, $t* res) {
|
||||
// $t res;
|
||||
if (!root) {
|
||||
const char *error_ptr = cJSON_GetErrorPtr();
|
||||
if (error_ptr != NULL) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
'
|
||||
// Code gen encoder
|
||||
enc += '
|
||||
cJSON* $enc_fn.name($t val) {
|
||||
cJSON* $enc_fn.name($t val) {
|
||||
cJSON *o = cJSON_CreateObject();
|
||||
string res = tos2("");
|
||||
string res = tos2("");
|
||||
'
|
||||
// Handle arrays
|
||||
if t.starts_with('array_') {
|
||||
|
@ -144,7 +144,7 @@ fn (p mut Parser) decode_array(array_type string) string {
|
|||
const cJSON *jsval = NULL;
|
||||
cJSON_ArrayForEach(jsval, root)
|
||||
{
|
||||
$s
|
||||
$s
|
||||
array__push(res, &val);
|
||||
}
|
||||
'
|
||||
|
@ -167,7 +167,7 @@ fn (p &Parser) encode_array(array_type string) string {
|
|||
o = cJSON_CreateArray();
|
||||
for (int i = 0; i < val.len; 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_indent int
|
||||
fmt_line_empty bool
|
||||
prev_tok Token
|
||||
prev_tok Token
|
||||
}
|
||||
|
||||
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() {
|
||||
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) {
|
||||
s.line_nr++
|
||||
}
|
||||
|
@ -216,10 +216,10 @@ fn (s mut Scanner) skip_whitespace() {
|
|||
}
|
||||
|
||||
fn (s mut Scanner) scan() ScanRes {
|
||||
if s.line_comment != '' {
|
||||
if s.line_comment != '' {
|
||||
//s.fgenln('// LOL "$s.line_comment"')
|
||||
//s.line_comment = ''
|
||||
}
|
||||
//s.line_comment = ''
|
||||
}
|
||||
if s.started {
|
||||
s.pos++
|
||||
}
|
||||
|
@ -388,11 +388,11 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
case `,`:
|
||||
return scan_res(.comma, '')
|
||||
case `@`:
|
||||
s.pos++
|
||||
s.pos++
|
||||
name := s.ident_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)
|
||||
case `\r`:
|
||||
if nextc == `\n` {
|
||||
|
@ -477,7 +477,7 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
else if nextc == `>` {
|
||||
s.pos++
|
||||
return scan_res(.arrow, '')
|
||||
}
|
||||
}
|
||||
else {
|
||||
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.line_comment.trim_space()
|
||||
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()
|
||||
}
|
||||
// Multiline comments
|
||||
|
@ -553,13 +553,13 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
$if windows {
|
||||
if c == `\0` {
|
||||
return scan_res(.eof, '')
|
||||
}
|
||||
}
|
||||
mut msg := 'invalid character `${c.str()}`'
|
||||
}
|
||||
}
|
||||
mut msg := 'invalid character `${c.str()}`'
|
||||
if c == `"` {
|
||||
msg += ', use \' to denote strings'
|
||||
}
|
||||
s.error(msg)
|
||||
msg += ', use \' to denote strings'
|
||||
}
|
||||
s.error(msg)
|
||||
return scan_res(.eof, '')
|
||||
}
|
||||
|
||||
|
@ -797,17 +797,17 @@ fn contains_capital(s string) bool {
|
|||
}
|
||||
|
||||
// HTTPRequest bad
|
||||
// HttpRequest good
|
||||
// HttpRequest good
|
||||
fn good_type_name(s string) bool {
|
||||
if s.len < 4 {
|
||||
return true
|
||||
}
|
||||
for i in 2 .. s.len {
|
||||
return true
|
||||
}
|
||||
for i in 2 .. s.len {
|
||||
if s[i].is_capital() && s[i-1].is_capital() && s[i-2].is_capital() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
|
180
compiler/table.v
180
compiler/table.v
|
@ -4,15 +4,15 @@
|
|||
|
||||
module main
|
||||
|
||||
import math
|
||||
import strings
|
||||
import math
|
||||
import strings
|
||||
|
||||
struct Table {
|
||||
mut:
|
||||
types []Type
|
||||
consts []Var
|
||||
fns map[string]Fn
|
||||
generic_fns []GenTable //map[string]GenTable // generic_fns['listen_and_serve'] == ['Blog', 'Forum']
|
||||
fns map[string]Fn
|
||||
generic_fns []GenTable //map[string]GenTable // generic_fns['listen_and_serve'] == ['Blog', 'Forum']
|
||||
obf_ids map[string]int // obf_ids['myfunction'] == 23
|
||||
modules []string // List of all modules registered by the application
|
||||
imports []string // List of all imports
|
||||
|
@ -23,9 +23,9 @@ mut:
|
|||
}
|
||||
|
||||
struct GenTable {
|
||||
fn_name string
|
||||
types []string
|
||||
}
|
||||
fn_name string
|
||||
types []string
|
||||
}
|
||||
|
||||
// Holds import information scoped to the parsed file
|
||||
struct FileImportTable {
|
||||
|
@ -36,8 +36,8 @@ mut:
|
|||
}
|
||||
|
||||
enum AccessMod {
|
||||
private // private immutable
|
||||
private_mut // private mutable
|
||||
private // private immutable
|
||||
private_mut // private mutable
|
||||
public // public immutable (readonly)
|
||||
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)
|
||||
|
@ -54,13 +54,13 @@ mut:
|
|||
is_c bool // C.FI.le
|
||||
is_interface bool
|
||||
is_enum bool
|
||||
enum_vals []string
|
||||
gen_types []string
|
||||
enum_vals []string
|
||||
gen_types []string
|
||||
// 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.
|
||||
// This information is needed in the first pass.
|
||||
is_placeholder bool
|
||||
gen_str bool // needs `.str()` method generation
|
||||
gen_str bool // needs `.str()` method generation
|
||||
}
|
||||
|
||||
// For debugging types
|
||||
|
@ -109,12 +109,12 @@ fn (f Fn) str() string {
|
|||
}
|
||||
|
||||
fn (t &Table) debug_fns() string {
|
||||
mut s := strings.new_builder(1000)
|
||||
mut s := strings.new_builder(1000)
|
||||
for _, f in t.fns {
|
||||
s.writeln(f.name)
|
||||
}
|
||||
return s.str()
|
||||
}
|
||||
s.writeln(f.name)
|
||||
}
|
||||
return s.str()
|
||||
}
|
||||
|
||||
// fn (types array_Type) print_to_file(f string) {
|
||||
// }
|
||||
|
@ -124,23 +124,23 @@ const (
|
|||
)
|
||||
|
||||
fn is_number_type(typ string) bool {
|
||||
return typ in number_types
|
||||
return typ in number_types
|
||||
}
|
||||
|
||||
fn is_float_type(typ string) bool {
|
||||
return typ in float_types
|
||||
return typ in float_types
|
||||
}
|
||||
|
||||
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 {
|
||||
mut t := &Table {
|
||||
obf_ids: map[string]int
|
||||
fns: map[string]Fn
|
||||
//generic_fns: map[string]GenTable{}
|
||||
generic_fns: []GenTable
|
||||
obf_ids: map[string]int
|
||||
fns: map[string]Fn
|
||||
//generic_fns: map[string]GenTable{}
|
||||
generic_fns: []GenTable
|
||||
obfuscate: obfuscate
|
||||
file_imports: []FileImportTable
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ fn (t mut Table) register_const(name, typ, mod string, is_imported bool) {
|
|||
typ: typ
|
||||
is_const: true
|
||||
is_import_const: is_imported
|
||||
mod: mod
|
||||
mod: mod
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,17 +234,17 @@ fn (p mut Parser) register_global(name, typ string) {
|
|||
typ: typ
|
||||
is_const: true
|
||||
is_global: true
|
||||
mod: p.mod
|
||||
is_mut: true
|
||||
mod: p.mod
|
||||
is_mut: true
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
mut typ := typ_
|
||||
mut typ := typ_
|
||||
// 'byte*' => look up 'byte', but don't mess up fns
|
||||
if typ.ends_with('*') && !typ.contains(' ') {
|
||||
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 {
|
||||
f := t.fns[name]
|
||||
if !isnil(f.name.str) {
|
||||
return f
|
||||
}
|
||||
f := t.fns[name]
|
||||
if !isnil(f.name.str) {
|
||||
return f
|
||||
}
|
||||
return Fn{}
|
||||
}
|
||||
|
||||
fn (t &Table) known_fn(name string) bool {
|
||||
f := t.find_fn(name)
|
||||
return f.name != ''
|
||||
f := t.find_fn(name)
|
||||
return f.name != ''
|
||||
}
|
||||
|
||||
fn (t &Table) known_const(name string) bool {
|
||||
|
@ -318,10 +318,10 @@ if parent == 'array' {
|
|||
mod = 'builtin'
|
||||
}
|
||||
*/
|
||||
t.types << Type {
|
||||
t.types << Type {
|
||||
name: typ
|
||||
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 {
|
||||
return name in t.enum_vals
|
||||
return name in t.enum_vals
|
||||
}
|
||||
|
||||
fn (t &Type) find_field(name string) Var {
|
||||
|
@ -425,7 +425,7 @@ fn (t &Type) find_method(name string) Fn {
|
|||
return Fn{}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
fn (t mut Type) add_gen_type(type_name string) {
|
||||
// println('add_gen_type($s)')
|
||||
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
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
fn (p &Parser) find_type(name string) &Type {
|
||||
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 {
|
||||
mut name := name_
|
||||
mut name := name_
|
||||
if name.ends_with('*') && !name.contains(' ') {
|
||||
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 {
|
||||
mut got := got_
|
||||
mut expected := expected_
|
||||
mut got := got_
|
||||
mut expected := expected_
|
||||
p.log('check types got="$got" exp="$expected" ')
|
||||
if p.pref.translated {
|
||||
return true
|
||||
|
@ -505,13 +505,13 @@ fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool {
|
|||
}
|
||||
if got=='byte*' && expected=='byteptr' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if got=='int' && expected=='byte*' {
|
||||
return true
|
||||
}
|
||||
//if got=='int' && expected=='voidptr*' {
|
||||
//return true
|
||||
//}
|
||||
//return true
|
||||
//}
|
||||
// byteptr += int
|
||||
if got=='int' && expected=='byteptr' {
|
||||
return true
|
||||
|
@ -593,7 +593,7 @@ fn type_default(typ string) string {
|
|||
if typ.ends_with('*') {
|
||||
return '0'
|
||||
}
|
||||
// User struct defined in another module.
|
||||
// User struct defined in another module.
|
||||
if typ.contains('__') {
|
||||
return 'STRUCT_DEFAULT_VALUE'
|
||||
}
|
||||
|
@ -617,7 +617,7 @@ fn type_default(typ string) string {
|
|||
case 'byteptr': return '0'
|
||||
case 'voidptr': return '0'
|
||||
}
|
||||
return 'STRUCT_DEFAULT_VALUE'
|
||||
return 'STRUCT_DEFAULT_VALUE'
|
||||
}
|
||||
|
||||
// TODO PERF O(n)
|
||||
|
@ -632,7 +632,7 @@ fn (t &Table) is_interface(name string) bool {
|
|||
|
||||
// Do we have fn main()?
|
||||
fn (t &Table) main_exists() bool {
|
||||
for _, f in t.fns {
|
||||
for _, f in t.fns {
|
||||
if f.name == 'main' {
|
||||
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 {
|
||||
x := val.int()
|
||||
x := val.int()
|
||||
switch typ {
|
||||
case 'byte', 'u8': return 0 <= x && x <= math.MaxU8
|
||||
case 'u16': return 0 <= x && x <= math.MaxU16
|
||||
//case 'u32': return 0 <= x && x <= math.MaxU32
|
||||
//case 'u64': return 0 <= x && x <= math.MaxU64
|
||||
//////////////
|
||||
case 'i8': return math.MinI8 <= x && x <= math.MaxI8
|
||||
case 'i16': return math.MinI16 <= x && x <= math.MaxI16
|
||||
case 'int', 'i32': return math.MinI32 <= x && x <= math.MaxI32
|
||||
//case 'i64':
|
||||
//x64 := val.i64()
|
||||
//return i64(-(1<<63)) <= x64 && x64 <= i64((1<<63)-1)
|
||||
}
|
||||
return true
|
||||
case 'byte', 'u8': return 0 <= x && x <= math.MaxU8
|
||||
case 'u16': return 0 <= x && x <= math.MaxU16
|
||||
//case 'u32': return 0 <= x && x <= math.MaxU32
|
||||
//case 'u64': return 0 <= x && x <= math.MaxU64
|
||||
//////////////
|
||||
case 'i8': return math.MinI8 <= x && x <= math.MaxI8
|
||||
case 'i16': return math.MinI16 <= x && x <= math.MaxI16
|
||||
case 'int', 'i32': return math.MinI32 <= x && x <= math.MaxI32
|
||||
//case 'i64':
|
||||
//x64 := val.i64()
|
||||
//return i64(-(1<<63)) <= x64 && x64 <= i64((1<<63)-1)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn (t mut Table) register_generic_fn(fn_name string) {
|
||||
t.generic_fns << GenTable{fn_name, []string}
|
||||
}
|
||||
fn (t mut Table) register_generic_fn(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 {
|
||||
if f.fn_name == fn_name {
|
||||
return f.types
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
panic('function $fn_name not found')
|
||||
}
|
||||
}
|
||||
|
||||
// `foo<Bar>()`
|
||||
// fn_name == 'foo'
|
||||
// typ == 'Bar'
|
||||
fn (t mut Table) register_generic_fn_type(fn_name, typ string) {
|
||||
// typ == 'Bar'
|
||||
fn (t mut Table) register_generic_fn_type(fn_name, typ string) {
|
||||
for i, f in t.generic_fns {
|
||||
if f.fn_name == fn_name {
|
||||
t.generic_fns[i].types << typ
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
t.generic_fns[i].types << typ
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) typ_to_fmt(typ string, level int) string {
|
||||
t := p.table.find_type(typ)
|
||||
if t.is_enum {
|
||||
if t.is_enum {
|
||||
return '%d'
|
||||
}
|
||||
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')
|
||||
default:
|
||||
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 ''
|
||||
}
|
||||
|
||||
|
@ -818,7 +818,7 @@ fn (table &Table) qualify_module(mod string, file_path string) string {
|
|||
fn new_file_import_table(file_path string) *FileImportTable {
|
||||
return &FileImportTable{
|
||||
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) {
|
||||
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}".')
|
||||
}
|
||||
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 {
|
||||
return alias in fit.imports
|
||||
return alias in fit.imports
|
||||
}
|
||||
|
||||
fn (fit &FileImportTable) is_aliased(mod string) bool {
|
||||
for _, val in fit.imports {
|
||||
for _, val in fit.imports {
|
||||
if val == mod {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -6,35 +6,35 @@ module main
|
|||
|
||||
enum Token {
|
||||
eof
|
||||
name // user
|
||||
number // 123
|
||||
str // 'foo'
|
||||
str_inter // 'name=$user.name'
|
||||
chartoken // `A`
|
||||
name // user
|
||||
number // 123
|
||||
str // 'foo'
|
||||
str_inter // 'name=$user.name'
|
||||
chartoken // `A`
|
||||
plus
|
||||
minus
|
||||
mul
|
||||
div
|
||||
mod
|
||||
xor // ^
|
||||
pipe // |
|
||||
inc // ++
|
||||
dec // --
|
||||
and // &&
|
||||
logical_or
|
||||
not
|
||||
xor // ^
|
||||
pipe // |
|
||||
inc // ++
|
||||
dec // --
|
||||
and // &&
|
||||
logical_or
|
||||
not
|
||||
bit_not
|
||||
question
|
||||
comma
|
||||
semicolon
|
||||
colon
|
||||
arrow // =>
|
||||
arrow // =>
|
||||
amp
|
||||
hash
|
||||
dollar
|
||||
left_shift
|
||||
righ_shift
|
||||
//at // @
|
||||
//at // @
|
||||
// = := += -=
|
||||
assign
|
||||
decl_assign
|
||||
|
@ -63,10 +63,10 @@ enum Token {
|
|||
ge
|
||||
le
|
||||
// comments
|
||||
//line_com
|
||||
//mline_com
|
||||
nl
|
||||
dot
|
||||
//line_com
|
||||
//mline_com
|
||||
nl
|
||||
dot
|
||||
dotdot
|
||||
// keywords
|
||||
keyword_beg
|
||||
|
@ -77,8 +77,8 @@ enum Token {
|
|||
key_case
|
||||
key_const
|
||||
key_continue
|
||||
key_default
|
||||
key_defer
|
||||
key_default
|
||||
key_defer
|
||||
key_else
|
||||
key_embed
|
||||
key_enum
|
||||
|
@ -87,26 +87,26 @@ enum Token {
|
|||
func
|
||||
key_global
|
||||
key_go
|
||||
key_goto
|
||||
key_if
|
||||
key_goto
|
||||
key_if
|
||||
key_import
|
||||
key_import_const
|
||||
key_in
|
||||
key_interface
|
||||
key_match
|
||||
key_import_const
|
||||
key_in
|
||||
key_interface
|
||||
key_match
|
||||
key_module
|
||||
key_mut
|
||||
key_return
|
||||
key_select
|
||||
key_select
|
||||
key_sizeof
|
||||
key_struct
|
||||
key_switch
|
||||
key_switch
|
||||
key_true
|
||||
key_type
|
||||
//typeof
|
||||
key_type
|
||||
//typeof
|
||||
key_orelse
|
||||
key_union
|
||||
key_pub
|
||||
key_pub
|
||||
key_static
|
||||
keyword_end
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ enum Token {
|
|||
// build_keys genereates a map with keywords' string values:
|
||||
// Keywords['return'] == .key_return
|
||||
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++ {
|
||||
key := TokenStr[t]
|
||||
res[key] = int(t)
|
||||
|
@ -122,7 +122,7 @@ fn build_keys() map[string]int {
|
|||
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 {
|
||||
mut s := [''; NrTokens]
|
||||
s[Token.keyword_beg] = ''
|
||||
|
@ -246,9 +246,9 @@ fn (t Token) str() string {
|
|||
|
||||
fn (t Token) is_decl() bool {
|
||||
// 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]
|
||||
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_const || t == .key_import_const || t == .key_pub || t == .eof
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ fn (t Token) is_decl() bool {
|
|||
const (
|
||||
AssignTokens = [
|
||||
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.or_assign, Token.and_assign, Token.righ_shift_assign,
|
||||
Token.left_shift_assign
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module main
|
||||
module main
|
||||
|
||||
import strings
|
||||
import strings
|
||||
|
||||
// fmt helpers
|
||||
fn (scanner mut Scanner) fgen(s_ string) {
|
||||
mut s := s_
|
||||
mut s := s_
|
||||
if scanner.fmt_line_empty {
|
||||
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) {
|
||||
mut s := s_
|
||||
mut s := s_
|
||||
if scanner.fmt_line_empty {
|
||||
s = strings.repeat(`\t`, scanner.fmt_indent) + s
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ module builtin
|
|||
|
||||
struct string {
|
||||
//mut:
|
||||
//hash_cache int
|
||||
//hash_cache int
|
||||
pub:
|
||||
str byteptr
|
||||
len int
|
||||
|
@ -22,10 +22,10 @@ pub:
|
|||
// For C strings only
|
||||
fn C.strlen(s byteptr) int
|
||||
|
||||
fn todo() { }
|
||||
fn todo() { }
|
||||
|
||||
// Converts a C string to a V string.
|
||||
// String data is reused, not copied.
|
||||
// Converts a C string to a V string.
|
||||
// String data is reused, not copied.
|
||||
pub fn tos(s byteptr, len int) string {
|
||||
// This should never happen.
|
||||
if isnil(s) {
|
||||
|
@ -44,8 +44,8 @@ pub fn tos_clone(s byteptr) string {
|
|||
return tos2(s).clone()
|
||||
}
|
||||
|
||||
// Same as `tos`, but calculates the length. Called by `string(bytes)` casts.
|
||||
// Used only internally.
|
||||
// Same as `tos`, but calculates the length. Called by `string(bytes)` casts.
|
||||
// Used only internally.
|
||||
fn tos2(s byteptr) string {
|
||||
if isnil(s) {
|
||||
panic('tos2: nil string')
|
||||
|
@ -67,12 +67,12 @@ pub fn (a string) clone() string {
|
|||
return b
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
pub fn (s string) cstr() byteptr {
|
||||
clone := s.clone()
|
||||
return clone.str
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
pub fn (s string) replace(rep, with string) string {
|
||||
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)
|
||||
if val.len > 0 {
|
||||
res << val
|
||||
res << val
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ pub fn (s string) right(n int) string {
|
|||
return s.substr(n, s.len)
|
||||
}
|
||||
|
||||
// substr
|
||||
// substr
|
||||
pub fn (s string) substr(start, end int) string {
|
||||
if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
|
||||
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 := string {
|
||||
str: s.str + start
|
||||
len: len
|
||||
}
|
||||
*/
|
||||
*/
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -531,16 +531,16 @@ pub fn (ar []int) contains(val int) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
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++ {
|
||||
val := a[i]
|
||||
res[i] = val.str
|
||||
res[i] = val.str
|
||||
}
|
||||
return res
|
||||
return res
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
fn is_space(c byte) bool {
|
||||
return C.isspace(c)
|
||||
|
@ -563,8 +563,8 @@ pub fn (s string) trim_space() string {
|
|||
end--
|
||||
}
|
||||
if i > end + 1 {
|
||||
return s
|
||||
}
|
||||
return s
|
||||
}
|
||||
res := s.substr(i, end + 1)
|
||||
return res
|
||||
}
|
||||
|
@ -599,12 +599,12 @@ pub fn (s string) trim_left(cutset string) string {
|
|||
|
||||
pub fn (s string) trim_right(cutset string) string {
|
||||
if s.len == 0 {
|
||||
return s
|
||||
}
|
||||
mut pos := s.len - 1
|
||||
return s
|
||||
}
|
||||
mut pos := s.len - 1
|
||||
for s[pos] == cutset[0] {
|
||||
pos--
|
||||
}
|
||||
pos--
|
||||
}
|
||||
return s.left(pos+1)
|
||||
}
|
||||
|
||||
|
@ -743,14 +743,14 @@ pub fn (s string) free() {
|
|||
free(s.str)
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
fn (arr []string) free() {
|
||||
for s in arr {
|
||||
s.free()
|
||||
}
|
||||
C.free(arr.data)
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
// all_before('23:34:45.234', '.') == '23:34:45'
|
||||
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 {
|
||||
//mut h := s.hash_cache
|
||||
mut h := 0
|
||||
if h == 0 && s.len > 0 {
|
||||
for c in s {
|
||||
h = h * 31 + int(c)
|
||||
//mut h := s.hash_cache
|
||||
mut h := 0
|
||||
if h == 0 && s.len > 0 {
|
||||
for c in s {
|
||||
h = h * 31 + int(c)
|
||||
}
|
||||
}
|
||||
return h
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
pub fn (s string) bytes() []byte {
|
||||
|
|
Loading…
Reference in New Issue