2020-01-02 08:30:15 +01:00
|
|
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
|
|
|
// 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
|
|
|
|
v.types
|
|
|
|
)
|
|
|
|
|
2020-01-04 17:57:25 +01:00
|
|
|
pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) {
|
2020-01-02 08:30:15 +01:00
|
|
|
tok := p.tok
|
|
|
|
fn_name := p.check_name()
|
|
|
|
p.check(.lpar)
|
|
|
|
mut is_unknown := false
|
2020-01-06 16:13:12 +01:00
|
|
|
is_unknown = false
|
2020-01-02 08:30:15 +01:00
|
|
|
mut args := []ast.Expr
|
2020-01-06 16:13:12 +01:00
|
|
|
mut return_ti := types.void_ti
|
2020-01-02 08:30:15 +01:00
|
|
|
if f := p.table.find_fn(fn_name) {
|
2020-01-07 13:10:05 +01:00
|
|
|
// println('found fn $fn_name')
|
2020-01-04 17:57:25 +01:00
|
|
|
return_ti = f.return_ti
|
2020-01-02 08:30:15 +01:00
|
|
|
for i, arg in f.args {
|
2020-01-04 17:57:25 +01:00
|
|
|
e,ti := p.expr(0)
|
2020-01-06 16:13:12 +01:00
|
|
|
if !types.check(&arg.ti, &ti) {
|
|
|
|
p.error('cannot use type `$ti.name` as type `$arg.ti.name` in argument to `$fn_name`')
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
|
|
|
args << e
|
|
|
|
if i < f.args.len - 1 {
|
|
|
|
p.check(.comma)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if p.tok.kind == .comma {
|
|
|
|
p.error('too many arguments in call to `$fn_name`')
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
is_unknown = true
|
|
|
|
p.warn('unknown function `$fn_name`')
|
|
|
|
for p.tok.kind != .rpar {
|
|
|
|
e,_ := p.expr(0)
|
|
|
|
args << e
|
|
|
|
if p.tok.kind != .rpar {
|
|
|
|
p.check(.comma)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p.check(.rpar)
|
|
|
|
node := ast.CallExpr{
|
|
|
|
name: fn_name
|
|
|
|
args: args
|
|
|
|
is_unknown: is_unknown
|
|
|
|
tok: tok
|
2020-01-06 16:13:12 +01:00
|
|
|
// typ: return_ti
|
2020-01-02 20:09:15 +01:00
|
|
|
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
|
|
|
if is_unknown {
|
|
|
|
p.table.unknown_calls << node
|
|
|
|
}
|
2020-01-04 17:57:25 +01:00
|
|
|
return node,return_ti
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
|
|
|
|
2020-01-07 01:08:24 +01:00
|
|
|
pub fn (p mut Parser) call_args() []ast.Expr {
|
|
|
|
mut args := []ast.Expr
|
|
|
|
for p.tok.kind != .rpar {
|
|
|
|
e,_ := p.expr(0)
|
|
|
|
args << e
|
|
|
|
if p.tok.kind != .rpar {
|
|
|
|
p.check(.comma)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p.check(.rpar)
|
|
|
|
return args // ,types.void_ti
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:30:15 +01:00
|
|
|
fn (p mut Parser) fn_decl() ast.FnDecl {
|
2020-01-02 20:09:15 +01:00
|
|
|
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-01-02 20:09:15 +01:00
|
|
|
// Receiver?
|
|
|
|
mut rec_name := ''
|
2020-01-07 13:10:05 +01:00
|
|
|
mut is_method := false
|
2020-01-06 16:13:12 +01:00
|
|
|
mut rec_ti := types.void_ti
|
2020-01-02 20:09:15 +01:00
|
|
|
if p.tok.kind == .lpar {
|
2020-01-07 13:10:05 +01:00
|
|
|
is_method = true
|
2020-01-02 20:09:15 +01:00
|
|
|
p.next()
|
|
|
|
rec_name = p.check_name()
|
|
|
|
if p.tok.kind == .key_mut {
|
|
|
|
p.next()
|
|
|
|
}
|
2020-01-04 17:57:25 +01:00
|
|
|
rec_ti = p.parse_ti()
|
2020-01-02 20:09:15 +01:00
|
|
|
p.table.register_var(table.Var{
|
|
|
|
name: rec_name
|
2020-01-04 17:57:25 +01:00
|
|
|
ti: rec_ti
|
2020-01-02 20:09:15 +01:00
|
|
|
})
|
|
|
|
p.check(.rpar)
|
|
|
|
}
|
2020-01-02 08:30:15 +01:00
|
|
|
name := p.check_name()
|
|
|
|
// println('fn decl $name')
|
|
|
|
p.check(.lpar)
|
|
|
|
// Args
|
|
|
|
mut args := []table.Var
|
|
|
|
mut ast_args := []ast.Arg
|
|
|
|
for p.tok.kind != .rpar {
|
2020-01-02 20:09:15 +01:00
|
|
|
mut arg_names := [p.check_name()]
|
|
|
|
// `a, b, c int`
|
|
|
|
for p.tok.kind == .comma {
|
|
|
|
p.check(.comma)
|
|
|
|
arg_names << p.check_name()
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
2020-01-04 17:57:25 +01:00
|
|
|
ti := p.parse_ti()
|
2020-01-02 20:09:15 +01:00
|
|
|
for arg_name in arg_names {
|
|
|
|
arg := table.Var{
|
|
|
|
name: arg_name
|
2020-01-04 17:57:25 +01:00
|
|
|
ti: ti
|
2020-01-02 20:09:15 +01:00
|
|
|
}
|
|
|
|
args << arg
|
|
|
|
p.table.register_var(arg)
|
|
|
|
ast_args << ast.Arg{
|
2020-01-04 17:57:25 +01:00
|
|
|
ti: ti
|
2020-01-02 20:09:15 +01:00
|
|
|
name: arg_name
|
|
|
|
}
|
2020-01-07 15:46:57 +01:00
|
|
|
if ti.kind == .variadic && p.tok.kind == .comma {
|
2020-01-07 12:10:07 +01:00
|
|
|
p.error('cannot use ...(variadic) with non-final parameter $arg_name')
|
|
|
|
}
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
|
|
|
if p.tok.kind != .rpar {
|
|
|
|
p.check(.comma)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p.check(.rpar)
|
|
|
|
// Return type
|
2020-01-06 16:13:12 +01:00
|
|
|
mut ti := types.void_ti
|
2020-01-07 12:10:07 +01:00
|
|
|
if p.tok.kind in [.name, .lpar] {
|
2020-01-04 17:57:25 +01:00
|
|
|
ti = p.parse_ti()
|
|
|
|
p.return_ti = ti
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
2020-01-07 13:10:05 +01:00
|
|
|
if !is_method {
|
|
|
|
p.table.register_fn(table.Fn{
|
|
|
|
name: name
|
|
|
|
args: args
|
|
|
|
return_ti: ti
|
|
|
|
})
|
|
|
|
}
|
2020-01-02 08:30:15 +01:00
|
|
|
stmts := p.parse_block()
|
|
|
|
return ast.FnDecl{
|
|
|
|
name: name
|
|
|
|
stmts: stmts
|
2020-01-04 17:57:25 +01:00
|
|
|
ti: ti
|
2020-01-02 08:30:15 +01:00
|
|
|
args: ast_args
|
2020-01-02 20:09:15 +01:00
|
|
|
is_pub: is_pub
|
|
|
|
receiver: ast.Field{
|
|
|
|
name: rec_name
|
2020-01-04 17:57:25 +01:00
|
|
|
ti: rec_ti
|
2020-01-02 20:09:15 +01:00
|
|
|
}
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (p &Parser) check_fn_calls() {
|
2020-01-02 20:09:15 +01:00
|
|
|
println('check fn calls2')
|
2020-01-02 08:30:15 +01:00
|
|
|
for call in p.table.unknown_calls {
|
|
|
|
f := p.table.find_fn(call.name) or {
|
|
|
|
p.error_at_line('unknown function `$call.name`', call.tok.line_nr)
|
|
|
|
return
|
|
|
|
}
|
2020-01-02 08:37:41 +01:00
|
|
|
println(f.name)
|
2020-01-06 16:13:12 +01:00
|
|
|
// println(f.return_ti.name)
|
2020-01-02 20:09:15 +01:00
|
|
|
// println('IN AST typ=' + call.typ.name)
|
2020-01-02 08:30:15 +01:00
|
|
|
}
|
|
|
|
}
|