mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
new enum syntax; update the compiler (p.tok == .name
)
This commit is contained in:
152
compiler/fn.v
152
compiler/fn.v
@ -114,7 +114,7 @@ fn new_fn(pkg 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 ')
|
||||
is_pub := p.tok == PUB
|
||||
is_pub := p.tok == .key_pub
|
||||
is_live := p.attr == 'live' && !p.pref.is_so
|
||||
if is_live && !p.pref.is_live {
|
||||
p.error('run `v -live program.v` if you want to use [live] functions')
|
||||
@ -124,15 +124,15 @@ fn (p mut Parser) fn_decl() {
|
||||
}
|
||||
p.returns = false
|
||||
p.next()
|
||||
mut f := new_fn(p.pkg, is_pub)
|
||||
mut f := new_fn(p.mod, is_pub)
|
||||
// Method receiver
|
||||
mut receiver_typ := ''
|
||||
if p.tok == LPAR {
|
||||
if p.tok == .lpar {
|
||||
f.is_method = true
|
||||
p.check(LPAR)
|
||||
p.check(.lpar)
|
||||
receiver_name := p.check_name()
|
||||
is_mut := p.tok == MUT
|
||||
is_amp := p.tok == AMP
|
||||
is_mut := p.tok == .key_mut
|
||||
is_amp := p.tok == .amp
|
||||
if is_mut || is_amp {
|
||||
p.check_space(p.tok)
|
||||
}
|
||||
@ -142,9 +142,9 @@ fn (p mut Parser) fn_decl() {
|
||||
p.error('invalid receiver type `$receiver_typ` (`$receiver_typ` is an interface)')
|
||||
}
|
||||
// Don't allow modifying types from a different module
|
||||
if !p.first_run() && !p.builtin_pkg && T.pkg != p.pkg {
|
||||
println('T.pkg=$T.pkg')
|
||||
println('pkg=$p.pkg')
|
||||
if !p.first_run() && !p.builtin_pkg && T.mod != p.mod {
|
||||
println('T.mod=$T.mod')
|
||||
println('pkg=$p.mod')
|
||||
p.error('cannot define new methods on non-local type `$receiver_typ`')
|
||||
}
|
||||
// (a *Foo) instead of (a mut Foo) is a common mistake
|
||||
@ -156,7 +156,7 @@ fn (p mut Parser) fn_decl() {
|
||||
if is_mut || is_amp {
|
||||
receiver_typ += '*'
|
||||
}
|
||||
p.check(RPAR)
|
||||
p.check(.rpar)
|
||||
p.fspace()
|
||||
receiver := Var {
|
||||
name: receiver_name
|
||||
@ -170,7 +170,7 @@ fn (p mut Parser) fn_decl() {
|
||||
f.args << receiver
|
||||
f.register_var(receiver)
|
||||
}
|
||||
if p.tok == PLUS || p.tok == MINUS || p.tok == MUL {
|
||||
if p.tok == .plus || p.tok == .minus || p.tok == .mul {
|
||||
f.name = p.tok.str()
|
||||
p.next()
|
||||
}
|
||||
@ -178,14 +178,14 @@ 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_pkg && p.pref.build_mode == default_mode
|
||||
// is_sig := p.pref.build_mode == default_mode && (p.builtin_pkg || p.file.contains(LANG_TMP))
|
||||
is_sig := p.is_sig()
|
||||
// println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg')
|
||||
if is_c {
|
||||
p.check(DOT)
|
||||
p.check(.dot)
|
||||
f.name = p.check_name()
|
||||
f.is_c = true
|
||||
}
|
||||
@ -198,7 +198,7 @@ fn (p mut Parser) fn_decl() {
|
||||
}
|
||||
}
|
||||
// simple_name := f.name
|
||||
// println('!SIMPLE=$simple_name')
|
||||
// println('!SIMP.le=$simple_name')
|
||||
// user.register() => User_register()
|
||||
has_receiver := receiver_typ.len > 0
|
||||
if receiver_typ != '' {
|
||||
@ -206,7 +206,7 @@ fn (p mut Parser) fn_decl() {
|
||||
}
|
||||
// full pkg function name
|
||||
// os.exit ==> os__exit()
|
||||
if !is_c && !p.builtin_pkg && p.pkg != 'main' && receiver_typ.len == 0 {
|
||||
if !is_c && !p.builtin_pkg && p.mod != 'main' && receiver_typ.len == 0 {
|
||||
f.name = p.prepend_pkg(f.name)
|
||||
}
|
||||
if p.first_run() && p.table.known_fn(f.name) && receiver_typ.len == 0 {
|
||||
@ -218,42 +218,42 @@ fn (p mut Parser) fn_decl() {
|
||||
}
|
||||
// Generic?
|
||||
mut is_generic := false
|
||||
if p.tok == LT {
|
||||
if p.tok == .lt {
|
||||
p.next()
|
||||
gen_type := p.check_name()
|
||||
if gen_type != 'T' {
|
||||
p.error('only `T` is allowed as a generic type for now')
|
||||
}
|
||||
p.check(GT)
|
||||
p.check(.gt)
|
||||
is_generic = true
|
||||
}
|
||||
// Args (...)
|
||||
p.fn_args(mut f)
|
||||
// Returns an error?
|
||||
if p.tok == NOT {
|
||||
if p.tok == .not {
|
||||
p.next()
|
||||
f.returns_error = true
|
||||
}
|
||||
// Returns a type?
|
||||
mut typ := 'void'
|
||||
if p.tok == NAME || p.tok == MUL || p.tok == AMP || p.tok == LSBR ||
|
||||
p.tok == QUESTION {
|
||||
if p.tok == .name || p.tok == .mul || p.tok == .amp || p.tok == .lsbr ||
|
||||
p.tok == .question {
|
||||
p.fgen(' ')
|
||||
// TODO In
|
||||
// if p.tok in [ NAME, MUL, AMP, LSBR ] {
|
||||
// if p.tok in [ .name, .mul, .amp, .lsbr ] {
|
||||
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)// || (p.tok == NAME && p.peek() != LCBR))
|
||||
(p.tok != .lcbr)// || (p.tok == .name && p.peek() != .lcbr))
|
||||
if is_fn_header {
|
||||
f.is_decl = true
|
||||
// println('GOT fn header $f.name')
|
||||
// println('.key_goT fn header $f.name')
|
||||
}
|
||||
// { required only in normal function declarations
|
||||
if !is_c && !is_sig && !is_fn_header {
|
||||
p.fgen(' ')
|
||||
p.check(LCBR)
|
||||
p.check(.lcbr)
|
||||
}
|
||||
// Register option ? type
|
||||
if typ.starts_with('Option_') {
|
||||
@ -262,7 +262,7 @@ fn (p mut Parser) fn_decl() {
|
||||
// Register function
|
||||
f.typ = typ
|
||||
mut str_args := f.str_args(p.table)
|
||||
// println('FN DECL $f.name typ=$f.typ str_args="$str_args"')
|
||||
// println('FN .decL $f.name typ=$f.typ str_args="$str_args"')
|
||||
// Special case for main() args
|
||||
if f.name == 'main' && !has_receiver {
|
||||
if str_args != '' || typ != 'void' {
|
||||
@ -305,7 +305,7 @@ fn (p mut Parser) fn_decl() {
|
||||
// println('fn decl !!!!!!! REG PH $receiver_typ')
|
||||
ttyp := Type {
|
||||
name: receiver_typ.replace('*', '')
|
||||
pkg: p.pkg
|
||||
mod: p.mod
|
||||
is_placeholder: true
|
||||
}
|
||||
p.table.register_type2(ttyp)
|
||||
@ -328,7 +328,7 @@ fn (p mut Parser) fn_decl() {
|
||||
}
|
||||
}
|
||||
// Live code reloading? Load all fns from .so
|
||||
if is_live && p.first_run() && p.pkg == 'main' {
|
||||
if is_live && p.first_run() && p.mod == 'main' {
|
||||
//println('ADDING SO FN $fn_name_cgen')
|
||||
p.cgen.so_fns << fn_name_cgen
|
||||
fn_name_cgen = '(* $fn_name_cgen )'
|
||||
@ -374,7 +374,7 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
|
||||
}
|
||||
// println('is_c=$is_c name=$f.name')
|
||||
if is_c || is_sig || is_fn_header {
|
||||
// println('IS SIG RETURNING tok=${p.strtok()}')
|
||||
// println('IS SIG .key_returnING tok=${p.strtok()}')
|
||||
p.fgenln('\n')
|
||||
return
|
||||
}
|
||||
@ -395,15 +395,15 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
|
||||
p.error('$f.name must return "$typ"')
|
||||
}
|
||||
// {} closed correctly? scope_level should be 0
|
||||
if p.pkg == 'main' {
|
||||
if p.mod == 'main' {
|
||||
// println(p.cur_fn.scope_level)
|
||||
}
|
||||
if p.cur_fn.scope_level > 2 {
|
||||
// p.error('unclosed {')
|
||||
}
|
||||
// Make sure all vars in this function are used (only in main for now)
|
||||
// if p.builtin_pkg || p.pkg == 'os' ||p.pkg=='http'{
|
||||
if p.pkg != 'main' {
|
||||
// if p.builtin_pkg || p.mod == 'os' ||p.mod=='http'{
|
||||
if p.mod != 'main' {
|
||||
p.genln('}')
|
||||
p.fgenln('\n')
|
||||
return
|
||||
@ -442,7 +442,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
|
||||
// println('\nfn_call $f.name is_method=$f.is_method receiver_type=$f.receiver_type')
|
||||
// p.print_tok()
|
||||
mut thread_name := ''
|
||||
// Normal function => just its name, method => TYPE_FNNAME
|
||||
// Normal function => just its name, method => TYPE_FN.name
|
||||
mut fn_name := f.name
|
||||
if f.is_method {
|
||||
receiver_type = receiver_type.replace('*', '')
|
||||
@ -454,7 +454,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
|
||||
p.genln('$arg_struct_name * $tmp_struct = malloc(sizeof($arg_struct_name));')
|
||||
mut arg_struct := 'typedef struct $arg_struct_name { '
|
||||
p.next()
|
||||
p.check(LPAR)
|
||||
p.check(.lpar)
|
||||
// str_args contains the args for the wrapper function:
|
||||
// wrapper(arg_struct * arg) { fn("arg->a, arg->b"); }
|
||||
mut str_args := ''
|
||||
@ -473,7 +473,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
|
||||
p.expression()
|
||||
p.genln(';')
|
||||
if i < f.args.len - 1 {
|
||||
p.check(COMMA)
|
||||
p.check(.comma)
|
||||
str_args += ','
|
||||
}
|
||||
}
|
||||
@ -486,7 +486,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
|
||||
// Create thread object
|
||||
tmp_nr := p.get_tmp_counter()
|
||||
thread_name = '_thread$tmp_nr'
|
||||
if p.os != WINDOWS {
|
||||
if p.os != .windows {
|
||||
p.genln('pthread_t $thread_name;')
|
||||
}
|
||||
tmp2 := p.get_tmp()
|
||||
@ -495,17 +495,17 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
|
||||
parg = ' $tmp_struct'
|
||||
}
|
||||
// Call the wrapper
|
||||
if p.os == WINDOWS {
|
||||
if p.os == .windows {
|
||||
p.genln(' CreateThread(0,0, $wrapper_name, $parg, 0,0);')
|
||||
}
|
||||
else {
|
||||
p.genln('int $tmp2 = pthread_create(& $thread_name, NULL, $wrapper_name, $parg);')
|
||||
}
|
||||
p.check(RPAR)
|
||||
p.check(.rpar)
|
||||
}
|
||||
|
||||
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.pkg != p.pkg {
|
||||
if !f.is_public && !f.is_c && !p.pref.is_test && !f.is_interface && f.pkg != p.mod {
|
||||
p.error('function `$f.name` is private')
|
||||
}
|
||||
p.calling_c = f.is_c
|
||||
@ -533,9 +533,9 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
|
||||
receiver := f.args.first()
|
||||
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')
|
||||
p.error('`$p.expr_var.name` is imkey_mut')
|
||||
}
|
||||
// if receiver is mutable 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('*')) {
|
||||
method_call += '& /* ? */'
|
||||
}
|
||||
@ -566,8 +566,8 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
|
||||
// for declaration
|
||||
// return an updated Fn object with args[] field set
|
||||
fn (p mut Parser) fn_args(f mut Fn) {
|
||||
p.check(LPAR)
|
||||
// TODO defer p.check(RPAR)
|
||||
p.check(.lpar)
|
||||
// TODO defer p.check(.rpar)
|
||||
if f.is_interface {
|
||||
int_arg := Var {
|
||||
typ: f.receiver_typ
|
||||
@ -575,9 +575,9 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||
f.args << int_arg
|
||||
}
|
||||
// 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 {
|
||||
for p.tok != RPAR {
|
||||
for p.tok != .rpar {
|
||||
typ := p.get_type()
|
||||
v := Var {
|
||||
typ: typ
|
||||
@ -587,24 +587,24 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||
}
|
||||
// f.register_var(v)
|
||||
f.args << v
|
||||
if p.tok == COMMA {
|
||||
if p.tok == .comma {
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
// (a int, b,c string) syntax
|
||||
for p.tok != RPAR {
|
||||
for p.tok != .rpar {
|
||||
mut names := [
|
||||
p.check_name()
|
||||
]
|
||||
// a,b,c int syntax
|
||||
for p.tok == COMMA {
|
||||
p.check(COMMA)
|
||||
for p.tok == .comma {
|
||||
p.check(.comma)
|
||||
p.fspace()
|
||||
names << p.check_name()
|
||||
}
|
||||
p.fspace()
|
||||
is_mut := p.tok == MUT
|
||||
is_mut := p.tok == .key_mut
|
||||
if is_mut {
|
||||
p.next()
|
||||
}
|
||||
@ -628,17 +628,17 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||
f.register_var(v)
|
||||
f.args << v
|
||||
}
|
||||
if p.tok == COMMA {
|
||||
if p.tok == .comma {
|
||||
p.next()
|
||||
}
|
||||
if p.tok == DOTDOT {
|
||||
if p.tok == .dotdot {
|
||||
f.args << Var {
|
||||
name: '..'
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
p.check(RPAR)
|
||||
p.check(.rpar)
|
||||
}
|
||||
|
||||
fn (p mut Parser) fn_call_args(f *Fn) *Fn {
|
||||
@ -646,16 +646,16 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
|
||||
// println('fn_call_args() name=$f.name args.len=$f.args.len')
|
||||
// C func. # of args is not known
|
||||
// if f.name.starts_with('c_') {
|
||||
p.check(LPAR)
|
||||
p.check(.lpar)
|
||||
if f.is_c {
|
||||
for p.tok != RPAR {
|
||||
for p.tok != .rpar {
|
||||
p.bool_expression()
|
||||
if p.tok == COMMA {
|
||||
if p.tok == .comma {
|
||||
p.gen(', ')
|
||||
p.check(COMMA)
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
p.check(RPAR)
|
||||
p.check(.rpar)
|
||||
return f
|
||||
}
|
||||
// Receiver - first arg
|
||||
@ -673,22 +673,27 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
|
||||
break
|
||||
}
|
||||
ph := p.cgen.add_placeholder()
|
||||
// ) here means not enough args were supplied
|
||||
if p.tok == RPAR {
|
||||
// `)` 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 key_mut, the caller needs to provide `mut`:
|
||||
// `arr := [1,2,3]; reverse(mut arr);`
|
||||
if arg.is_mut {
|
||||
if p.tok != MUT {
|
||||
p.error('`$arg.name` is a mutable argument, you need to provide `mut`: `$f.name(...mut a...)`')
|
||||
if p.tok != .key_mut {
|
||||
p.error('`$arg.name` is a key_mut argument, you need to provide `mut`: `$f.name(...mut a...)`')
|
||||
}
|
||||
if p.peek() != NAME {
|
||||
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
||||
if p.peek() != .name {
|
||||
p.error('`$arg.name` is a key_mut argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
||||
}
|
||||
p.check(MUT)
|
||||
p.check(.key_mut)
|
||||
}
|
||||
p.expected_type = arg.typ
|
||||
//TT := p.table.find_type(arg.typ)
|
||||
//if arg.typ.parent == 'int' {
|
||||
//p.expected_type =
|
||||
//}
|
||||
typ := p.bool_expression()
|
||||
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
||||
// function calls. `println(777)` => `printf("%d\n", 777)`
|
||||
@ -748,7 +753,7 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
|
||||
if ! (expected == 'void*' && got == 'int') &&
|
||||
! (expected == 'byte*' && got.contains(']byte')) &&
|
||||
! (expected == 'byte*' && got == 'string') {
|
||||
p.cgen.set_placeholder(ph, '& /*11 EXP:"$expected" GOT:"$got" */')
|
||||
p.cgen.set_placeholder(ph, '& /*11 EXP:"$expected" .key_goT:"$got" */')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -767,10 +772,10 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
|
||||
if i < f.args.len - 1 {
|
||||
// Handle 0 args passed to varargs
|
||||
is_vararg := i == f.args.len - 2 && f.args[i + 1].name == '..'
|
||||
if p.tok != COMMA && !is_vararg {
|
||||
if p.tok != .comma && !is_vararg {
|
||||
p.error('wrong number of arguments for $i,$arg.name fn `$f.name`: expected $f.args.len, but got less')
|
||||
}
|
||||
if p.tok == COMMA {
|
||||
if p.tok == .comma {
|
||||
p.fgen(', ')
|
||||
}
|
||||
if !is_vararg {
|
||||
@ -783,20 +788,19 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
|
||||
if f.args.len > 0 {
|
||||
last_arg := f.args.last()
|
||||
if last_arg.name == '..' {
|
||||
println('GOT VAR ARGS AFTER')
|
||||
for p.tok != RPAR {
|
||||
if p.tok == COMMA {
|
||||
for p.tok != .rpar {
|
||||
if p.tok == .comma {
|
||||
p.gen(',')
|
||||
p.check(COMMA)
|
||||
p.check(.comma)
|
||||
}
|
||||
p.bool_expression()
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.tok == COMMA {
|
||||
if p.tok == .comma {
|
||||
p.error('wrong number of arguments for fn `$f.name`: expected $f.args.len, but got more')
|
||||
}
|
||||
p.check(RPAR)
|
||||
p.check(.rpar)
|
||||
// p.gen(')')
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user