v/vlib/v/parser/fn.v

229 lines
4.3 KiB
V
Raw Normal View History

2020-01-23 21:04:46 +01:00
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
2020-01-02 08:30:15 +01:00
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module parser
import (
v.ast
v.table
)
pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) {
2020-01-02 08:30:15 +01:00
tok := p.tok
fn_name := p.check_name()
p.check(.lpar)
// mut return_ti := types.void_ti
2020-02-04 12:50:58 +01:00
args := p.call_args()
2020-01-02 08:30:15 +01:00
node := ast.CallExpr{
name: fn_name
args: args
// tok: tok
pos: tok.position()
2020-01-02 08:30:15 +01:00
}
2020-02-04 17:44:39 +01:00
if p.tok.kind == .key_orelse {
p.next()
p.parse_block()
}
if f := p.table.find_fn(fn_name) {
return node,f.return_type
2020-01-02 08:30:15 +01:00
}
typ := p.add_unresolved('${fn_name}()', node)
return node,typ
2020-01-02 08:30:15 +01:00
}
pub fn (p mut Parser) call_args() []ast.Expr {
mut args := []ast.Expr
for p.tok.kind != .rpar {
2020-02-04 12:50:58 +01:00
if p.tok.kind == .key_mut {
p.check(.key_mut)
}
e,_ := p.expr(0)
args << e
if p.tok.kind != .rpar {
p.check(.comma)
}
}
p.check(.rpar)
return args // ,table.void_ti
}
2020-02-04 09:54:15 +01:00
fn (p mut Parser) fn_decl() ast.FnDecl {
2020-02-04 17:44:39 +01:00
p.table.clear_vars()
is_pub := p.tok.kind == .key_pub
if is_pub {
p.next()
}
2020-01-02 08:30:15 +01:00
p.table.clear_vars()
p.check(.key_fn)
2020-02-04 09:54:15 +01:00
// C.
is_c := p.tok.kind == .name && p.tok.lit == 'C'
if is_c {
p.next()
p.check(.dot)
}
// Receiver?
mut rec_name := ''
2020-01-07 13:10:05 +01:00
mut is_method := false
mut rec_type := table.void_type
if p.tok.kind == .lpar {
2020-01-07 13:10:05 +01:00
is_method = true
p.next()
rec_name = p.check_name()
if p.tok.kind == .key_mut {
p.next()
}
rec_type = p.parse_type()
p.table.register_var(table.Var{
name: rec_name
typ: rec_type
})
p.check(.rpar)
}
mut name := ''
if p.tok.kind == .name {
2020-02-03 07:44:52 +01:00
// TODO high
name = p.check_name()
}
2020-02-03 07:44:52 +01:00
// <T>
if p.tok.kind == .lt {
p.next()
p.next()
p.check(.gt)
}
2020-01-02 08:30:15 +01:00
// println('fn decl $name')
p.check(.lpar)
// Args
mut args := []table.Var
2020-02-11 13:03:10 +01:00
ast_args,is_variadic := p.fn_args()
for ast_arg in ast_args {
var := table.Var{
name: ast_arg.name
typ: ast_arg.typ
}
args << var
p.table.register_var(var)
}
2020-02-04 12:50:58 +01:00
//
2020-02-11 13:03:10 +01:00
/*
arg := table.Var{
name: arg_name
typ: arg_type
}
args << arg
// p.table.register_var(arg)
2020-02-04 09:54:15 +01:00
arg := table.Var{
name: arg_name
typ: typ
2020-02-04 09:54:15 +01:00
}
args << arg
p.table.register_var(arg)
2020-02-11 13:03:10 +01:00
*/
2020-01-02 08:30:15 +01:00
// Return type
mut typ := table.void_type
2020-02-04 20:22:00 +01:00
if p.tok.kind in [.name, .lpar, .amp, .lsbr, .question] {
typ = p.parse_type()
2020-01-02 08:30:15 +01:00
}
2020-02-11 13:03:10 +01:00
p.return_type = typ
2020-01-08 10:19:12 +01:00
if is_method {
type_sym := p.table.get_type_symbol(rec_type)
ok := p.table.register_method(type_sym, table.Fn{
2020-01-08 10:19:12 +01:00
name: name
args: args
return_type: typ
2020-01-08 10:19:12 +01:00
})
if !ok {
p.error('expected Struct')
}
}
else {
2020-01-07 13:10:05 +01:00
p.table.register_fn(table.Fn{
name: name
args: args
return_type: typ
is_variadic: is_variadic
2020-02-07 07:34:18 +01:00
is_c: is_c
2020-01-07 13:10:05 +01:00
})
}
2020-02-04 09:54:15 +01:00
mut stmts := []ast.Stmt
if p.tok.kind == .lcbr {
stmts = p.parse_block()
}
2020-01-02 08:30:15 +01:00
return ast.FnDecl{
name: name
stmts: stmts
typ: typ
2020-01-02 08:30:15 +01:00
args: ast_args
is_pub: is_pub
is_variadic: is_variadic
receiver: ast.Field{
name: rec_name
typ: rec_type
}
2020-01-02 08:30:15 +01:00
}
}
2020-02-11 13:03:10 +01:00
fn (p mut Parser) fn_args() ([]ast.Arg,bool) {
mut args := []ast.Arg
mut is_variadic := false
// `int, int, string` (no names, just types)
types_only := p.tok.kind in [.amp] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) || p.peek_tok.kind == .rpar
if types_only {
p.warn('types only')
mut arg_no := 1
for p.tok.kind != .rpar {
arg_name := 'arg_$arg_no'
if p.tok.kind == .ellipsis {
p.check(.ellipsis)
is_variadic = true
}
arg_type := p.parse_type()
if p.tok.kind == .comma {
if is_variadic {
p.error('cannot use ...(variadic) with non-final parameter no $arg_no')
}
p.next()
}
args << ast.Arg{
name: arg_name
typ: arg_type
}
}
arg_no++
}
else {
for p.tok.kind != .rpar {
mut arg_names := [p.check_name()]
// `a, b, c int`
for p.tok.kind == .comma {
p.check(.comma)
arg_names << p.check_name()
}
if p.tok.kind == .key_mut {
p.check(.key_mut)
}
if p.tok.kind == .ellipsis {
p.check(.ellipsis)
is_variadic = true
}
typ := p.parse_type()
for arg_name in arg_names {
args << ast.Arg{
name: arg_name
typ: typ
}
// if typ.typ.kind == .variadic && p.tok.kind == .comma {
if is_variadic && p.tok.kind == .comma {
p.error('cannot use ...(variadic) with non-final parameter $arg_name')
}
}
if p.tok.kind != .rpar {
p.check(.comma)
}
}
}
p.check(.rpar)
return args,is_variadic
}