parser/checker: check capital letters in interface names/methods

pull/4752/head
Alexander Medvednikov 2020-05-06 12:26:00 +02:00
parent 99cf520bd4
commit cc66eb1194
6 changed files with 64 additions and 30 deletions

View File

@ -159,6 +159,7 @@ pub:
name string
field_names []string
methods []FnDecl
pos token.Position
}
pub struct StructInitField {

View File

@ -40,9 +40,13 @@ pub fn (node &FnDecl) str(t &table.Table) string {
f.write('fn ${receiver}${name}(')
for i, arg in node.args {
// skip receiver
// if (node.is_method || node.is_interface) && i == 0 {
if node.is_method && i == 0 {
continue
}
if arg.is_hidden {
continue
}
is_last_arg := i == node.args.len - 1
should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ || (node.is_variadic &&
i == node.args.len - 2)

View File

@ -90,7 +90,8 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) {
return
}
if !has_main_mod_file {
c.error('projet must include a `main` module or be a shared library (compile with `v -shared`)', token.Position{})
c.error('projet must include a `main` module or be a shared library (compile with `v -shared`)',
token.Position{})
} else if !has_main_fn {
c.error('function `main` must be declared in the main module', token.Position{})
}
@ -886,7 +887,8 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position
for imethod in inter_sym.methods {
if method := typ_sym.find_method(imethod.name) {
if !imethod.is_same_method_as(method) {
c.error('`$styp` incorrectly implements method `$imethod.name` of interface `$inter_sym.name`, expected `${c.table.fn_to_str(imethod)}`', pos)
c.error('`$styp` incorrectly implements method `$imethod.name` of interface `$inter_sym.name`, expected `${c.table.fn_to_str(imethod)}`',
pos)
}
continue
}
@ -1474,6 +1476,16 @@ fn (mut c Checker) stmt(node ast.Stmt) {
}
// ast.HashStmt {}
ast.Import {}
ast.InterfaceDecl {
if !it.name[0].is_capital() {
pos := token.Position{
line_nr: it.pos.line_nr
pos: it.pos.pos + 'interface'.len
len: it.name.len
}
c.error('interface name must begin with capital letter', pos)
}
}
ast.Module {
c.mod = it.name
c.is_builtin_mod = it.name == 'builtin'
@ -1561,8 +1573,8 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
ast.CastExpr {
it.expr_type = c.expr(it.expr)
sym := c.table.get_type_symbol(it.expr_type)
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] ||
sym.kind == .array && sym.name == 'array_byte') {
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || sym.kind ==
.array && sym.name == 'array_byte') {
type_name := c.table.type_to_str(it.expr_type)
c.error('cannot cast type `$type_name` to string', it.pos)
}

View File

@ -6,6 +6,7 @@ module parser
import v.ast
import v.table
import v.token
import v.util
fn (mut p Parser) struct_decl() ast.StructDecl {
start_pos := p.tok.position()
@ -255,6 +256,7 @@ fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
}
fn (mut p Parser) interface_decl() ast.InterfaceDecl {
start_pos := p.tok.position()
is_pub := p.tok.kind == .key_pub
if is_pub {
p.next()
@ -278,11 +280,15 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
for p.tok.kind != .rcbr && p.tok.kind != .eof {
line_nr := p.tok.line_nr
name := p.check_name()
if util.contains_capital(name) {
p.error('interface methods cannot contain uppercase letters, use snake_case instead')
}
// field_names << name
args2, _ := p.fn_args()
mut args := [table.Arg{
name: 'x'
typ: typ
is_hidden: true
}]
args << args2
mut method := ast.FnDecl{
@ -306,5 +312,6 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
return ast.InterfaceDecl{
name: interface_name
methods: methods
pos: start_pos
}
}

View File

@ -36,6 +36,7 @@ pub:
name string
is_mut bool
typ Type
is_hidden bool // interface first arg
}
pub struct Var {

View File

@ -1,4 +1,3 @@
struct Dog {
breed string
}
@ -46,11 +45,10 @@ fn (d Dog) name_detailed(pet_name string) string {
}
// do not add to Dog the utility function 'str', as a sample
fn test_todo() {
if true {}
else {}
if true {
} else {
}
}
fn perform_speak(a Animal) {
@ -65,11 +63,17 @@ fn perform_speak(a Animal) {
}
fn test_perform_speak() {
dog := Dog{breed: 'Labrador Retriever'}
dog := Dog{
breed: 'Labrador Retriever'
}
perform_speak(dog)
cat := Cat{breed: 'Persian'}
cat := Cat{
breed: 'Persian'
}
perform_speak(cat)
perform_speak(Cat{breed: 'Persian'})
perform_speak(Cat{
breed: 'Persian'
})
handle_animals([dog, cat])
/*
f := Foo {
@ -85,22 +89,24 @@ fn perform_name_detailed(a Animal) {
}
fn test_perform_name_detailed() {
dog := Dog{breed: 'Labrador Retriever'}
dog := Dog{
breed: 'Labrador Retriever'
}
println('Test on Dog: $dog ...')
perform_name_detailed(dog)
cat := Cat{}
println('Test on Cat: $cat ...')
perform_speak(cat)
println('Test on another Cat: ...')
perform_speak(Cat{breed: 'Persian'})
perform_speak(Cat{
breed: 'Persian'
})
println('Test (dummy/empty) on array of animals ...')
handle_animals([dog, cat])
}
fn handle_animals(a []Animal) {}
fn handle_animals(a []Animal) {
}
interface Register {
register()
@ -110,9 +116,11 @@ struct RegTest {
a int
}
fn (f RegTest) register() {}
fn (f RegTest) register() {
}
fn handle_reg(r Register) {}
fn handle_reg(r Register) {
}
fn test_register() {
f := RegTest{}
@ -125,7 +133,6 @@ interface Speaker2 {
speak()
}
struct Foo {
animal Animal
animals []Animal
@ -140,7 +147,9 @@ interface Animal {
fn test_interface_array() {
println('Test on array of animals ...')
mut animals := []Animal{}
animals = [ Cat{}, Dog{breed: 'Labrador Retriever'} ]
animals = [Cat{}, Dog{
breed: 'Labrador Retriever'
}]
animals << Cat{}
assert true
// TODO .str() from the real types should be called