parser/checker: check capital letters in interface names/methods
parent
99cf520bd4
commit
cc66eb1194
|
@ -159,6 +159,7 @@ pub:
|
||||||
name string
|
name string
|
||||||
field_names []string
|
field_names []string
|
||||||
methods []FnDecl
|
methods []FnDecl
|
||||||
|
pos token.Position
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StructInitField {
|
pub struct StructInitField {
|
||||||
|
|
|
@ -40,9 +40,13 @@ pub fn (node &FnDecl) str(t &table.Table) string {
|
||||||
f.write('fn ${receiver}${name}(')
|
f.write('fn ${receiver}${name}(')
|
||||||
for i, arg in node.args {
|
for i, arg in node.args {
|
||||||
// skip receiver
|
// skip receiver
|
||||||
|
// if (node.is_method || node.is_interface) && i == 0 {
|
||||||
if node.is_method && i == 0 {
|
if node.is_method && i == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if arg.is_hidden {
|
||||||
|
continue
|
||||||
|
}
|
||||||
is_last_arg := i == node.args.len - 1
|
is_last_arg := i == node.args.len - 1
|
||||||
should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ || (node.is_variadic &&
|
should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ || (node.is_variadic &&
|
||||||
i == node.args.len - 2)
|
i == node.args.len - 2)
|
||||||
|
|
|
@ -90,7 +90,8 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !has_main_mod_file {
|
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 {
|
} else if !has_main_fn {
|
||||||
c.error('function `main` must be declared in the main module', token.Position{})
|
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 {
|
for imethod in inter_sym.methods {
|
||||||
if method := typ_sym.find_method(imethod.name) {
|
if method := typ_sym.find_method(imethod.name) {
|
||||||
if !imethod.is_same_method_as(method) {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1474,6 +1476,16 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
// ast.HashStmt {}
|
// ast.HashStmt {}
|
||||||
ast.Import {}
|
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 {
|
ast.Module {
|
||||||
c.mod = it.name
|
c.mod = it.name
|
||||||
c.is_builtin_mod = it.name == 'builtin'
|
c.is_builtin_mod = it.name == 'builtin'
|
||||||
|
@ -1561,8 +1573,8 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
ast.CastExpr {
|
ast.CastExpr {
|
||||||
it.expr_type = c.expr(it.expr)
|
it.expr_type = c.expr(it.expr)
|
||||||
sym := c.table.get_type_symbol(it.expr_type)
|
sym := c.table.get_type_symbol(it.expr_type)
|
||||||
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] ||
|
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || sym.kind ==
|
||||||
sym.kind == .array && sym.name == 'array_byte') {
|
.array && sym.name == 'array_byte') {
|
||||||
type_name := c.table.type_to_str(it.expr_type)
|
type_name := c.table.type_to_str(it.expr_type)
|
||||||
c.error('cannot cast type `$type_name` to string', it.pos)
|
c.error('cannot cast type `$type_name` to string', it.pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ module parser
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.table
|
import v.table
|
||||||
import v.token
|
import v.token
|
||||||
|
import v.util
|
||||||
|
|
||||||
fn (mut p Parser) struct_decl() ast.StructDecl {
|
fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||||
start_pos := p.tok.position()
|
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 {
|
fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
|
start_pos := p.tok.position()
|
||||||
is_pub := p.tok.kind == .key_pub
|
is_pub := p.tok.kind == .key_pub
|
||||||
if is_pub {
|
if is_pub {
|
||||||
p.next()
|
p.next()
|
||||||
|
@ -278,11 +280,15 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
||||||
line_nr := p.tok.line_nr
|
line_nr := p.tok.line_nr
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
|
if util.contains_capital(name) {
|
||||||
|
p.error('interface methods cannot contain uppercase letters, use snake_case instead')
|
||||||
|
}
|
||||||
// field_names << name
|
// field_names << name
|
||||||
args2, _ := p.fn_args()
|
args2, _ := p.fn_args()
|
||||||
mut args := [table.Arg{
|
mut args := [table.Arg{
|
||||||
name: 'x'
|
name: 'x'
|
||||||
typ: typ
|
typ: typ
|
||||||
|
is_hidden: true
|
||||||
}]
|
}]
|
||||||
args << args2
|
args << args2
|
||||||
mut method := ast.FnDecl{
|
mut method := ast.FnDecl{
|
||||||
|
@ -306,5 +312,6 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
return ast.InterfaceDecl{
|
return ast.InterfaceDecl{
|
||||||
name: interface_name
|
name: interface_name
|
||||||
methods: methods
|
methods: methods
|
||||||
|
pos: start_pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub:
|
||||||
name string
|
name string
|
||||||
is_mut bool
|
is_mut bool
|
||||||
typ Type
|
typ Type
|
||||||
|
is_hidden bool // interface first arg
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Var {
|
pub struct Var {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
struct Dog {
|
struct Dog {
|
||||||
breed string
|
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
|
// do not add to Dog the utility function 'str', as a sample
|
||||||
|
|
||||||
|
|
||||||
fn test_todo() {
|
fn test_todo() {
|
||||||
if true {}
|
if true {
|
||||||
else {}
|
} else {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_speak(a Animal) {
|
fn perform_speak(a Animal) {
|
||||||
|
@ -65,11 +63,17 @@ fn perform_speak(a Animal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_perform_speak() {
|
fn test_perform_speak() {
|
||||||
dog := Dog{breed: 'Labrador Retriever'}
|
dog := Dog{
|
||||||
|
breed: 'Labrador Retriever'
|
||||||
|
}
|
||||||
perform_speak(dog)
|
perform_speak(dog)
|
||||||
cat := Cat{breed: 'Persian'}
|
cat := Cat{
|
||||||
|
breed: 'Persian'
|
||||||
|
}
|
||||||
perform_speak(cat)
|
perform_speak(cat)
|
||||||
perform_speak(Cat{breed: 'Persian'})
|
perform_speak(Cat{
|
||||||
|
breed: 'Persian'
|
||||||
|
})
|
||||||
handle_animals([dog, cat])
|
handle_animals([dog, cat])
|
||||||
/*
|
/*
|
||||||
f := Foo {
|
f := Foo {
|
||||||
|
@ -85,22 +89,24 @@ fn perform_name_detailed(a Animal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_perform_name_detailed() {
|
fn test_perform_name_detailed() {
|
||||||
dog := Dog{breed: 'Labrador Retriever'}
|
dog := Dog{
|
||||||
|
breed: 'Labrador Retriever'
|
||||||
|
}
|
||||||
println('Test on Dog: $dog ...')
|
println('Test on Dog: $dog ...')
|
||||||
perform_name_detailed(dog)
|
perform_name_detailed(dog)
|
||||||
|
|
||||||
cat := Cat{}
|
cat := Cat{}
|
||||||
println('Test on Cat: $cat ...')
|
println('Test on Cat: $cat ...')
|
||||||
perform_speak(cat)
|
perform_speak(cat)
|
||||||
|
|
||||||
println('Test on another Cat: ...')
|
println('Test on another Cat: ...')
|
||||||
perform_speak(Cat{breed: 'Persian'})
|
perform_speak(Cat{
|
||||||
|
breed: 'Persian'
|
||||||
|
})
|
||||||
println('Test (dummy/empty) on array of animals ...')
|
println('Test (dummy/empty) on array of animals ...')
|
||||||
handle_animals([dog, cat])
|
handle_animals([dog, cat])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_animals(a []Animal) {}
|
fn handle_animals(a []Animal) {
|
||||||
|
}
|
||||||
|
|
||||||
interface Register {
|
interface Register {
|
||||||
register()
|
register()
|
||||||
|
@ -110,9 +116,11 @@ struct RegTest {
|
||||||
a int
|
a int
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (f RegTest) register() {}
|
fn (f RegTest) register() {
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_reg(r Register) {}
|
fn handle_reg(r Register) {
|
||||||
|
}
|
||||||
|
|
||||||
fn test_register() {
|
fn test_register() {
|
||||||
f := RegTest{}
|
f := RegTest{}
|
||||||
|
@ -125,7 +133,6 @@ interface Speaker2 {
|
||||||
speak()
|
speak()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
animal Animal
|
animal Animal
|
||||||
animals []Animal
|
animals []Animal
|
||||||
|
@ -140,7 +147,9 @@ interface Animal {
|
||||||
fn test_interface_array() {
|
fn test_interface_array() {
|
||||||
println('Test on array of animals ...')
|
println('Test on array of animals ...')
|
||||||
mut animals := []Animal{}
|
mut animals := []Animal{}
|
||||||
animals = [ Cat{}, Dog{breed: 'Labrador Retriever'} ]
|
animals = [Cat{}, Dog{
|
||||||
|
breed: 'Labrador Retriever'
|
||||||
|
}]
|
||||||
animals << Cat{}
|
animals << Cat{}
|
||||||
assert true
|
assert true
|
||||||
// TODO .str() from the real types should be called
|
// TODO .str() from the real types should be called
|
||||||
|
|
Loading…
Reference in New Issue