Skip to content

Commit 7bcd25c

Browse files
yegappanchrisbra
authored andcommitted
patch 9.0.1885: Vim9: no support for abstract methods
Problem: Vim9: no support for abstract methods Solution: Add support for defining abstract methods in an abstract class closes: #13044 closes: #13046 Signed-off-by: Christian Brabandt <[email protected]> Co-authored-by: Yegappan Lakshmanan <[email protected]>
1 parent 86cfb39 commit 7bcd25c

9 files changed

Lines changed: 275 additions & 15 deletions

File tree

runtime/doc/tags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5850,6 +5850,7 @@ abandon editing.txt /*abandon*
58505850
abbreviations map.txt /*abbreviations*
58515851
abel.vim syntax.txt /*abel.vim*
58525852
abs() builtin.txt /*abs()*
5853+
abstract-method vim9class.txt /*abstract-method*
58535854
acos() builtin.txt /*acos()*
58545855
active-buffer windows.txt /*active-buffer*
58555856
ada#Create_Tags() ft_ada.txt /*ada#Create_Tags()*

runtime/doc/vim9class.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,16 @@ class, for which objects can be created. Example: >
358358
An abstract class is defined the same way as a normal class, except that it
359359
does not have any new() method. *E1359*
360360

361+
*abstract-method*
362+
An abstract method can be defined in an abstract class by using the "abstract"
363+
prefix when defining the function: >
364+
365+
abstract class Shape
366+
abstract def Draw()
367+
endclass
368+
369+
A class extending the abstract class must implement all the abstract methods.
370+
Class methods in an abstract class can also be abstract methods.
361371

362372
==============================================================================
363373

src/errors.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3495,6 +3495,12 @@ EXTERN char e_duplicate_member_str[]
34953495
INIT(= N_("E1369: Duplicate member: %s"));
34963496
EXTERN char e_cannot_define_new_function_as_static[]
34973497
INIT(= N_("E1370: Cannot define a \"new\" function as static"));
3498+
EXTERN char e_abstract_must_be_followed_by_def_or_static[]
3499+
INIT(= N_("E1371: Abstract must be followed by \"def\" or \"static\""));
3500+
EXTERN char e_abstract_method_in_concrete_class[]
3501+
INIT(= N_("E1372: Abstract method \"%s\" cannot be defined in a concrete class"));
3502+
EXTERN char e_abstract_method_str_not_found[]
3503+
INIT(= N_("E1373: Abstract method \"%s\" is not implemented"));
34983504
EXTERN char e_cannot_mix_positional_and_non_positional_str[]
34993505
INIT(= N_("E1400: Cannot mix positional and non-positional arguments: %s"));
35003506
EXTERN char e_fmt_arg_nr_unused_str[]

src/structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,7 @@ struct itf2class_S {
15151515

15161516
#define CLASS_INTERFACE 1
15171517
#define CLASS_EXTENDED 2 // another class extends this one
1518+
#define CLASS_ABSTRACT 4 // abstract class
15181519

15191520
// "class_T": used for v_class of typval of VAR_CLASS
15201521
// Also used for an interface (class_flags has CLASS_INTERFACE).
@@ -1875,6 +1876,7 @@ struct ufunc_S
18751876

18761877
#define FC_OBJECT 0x4000 // object method
18771878
#define FC_NEW 0x8000 // constructor
1879+
#define FC_ABSTRACT 0x10000 // abstract method
18781880

18791881
#define MAX_FUNC_ARGS 20 // maximum number of function arguments
18801882
#define VAR_SHORT_LEN 20 // short variable name length

src/testdir/test_vim9_class.vim

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4473,4 +4473,140 @@ enddef
44734473
" v9.CheckScriptSuccess(lines)
44744474
" enddef
44754475

4476+
" Test for abstract methods
4477+
def Test_abstract_method()
4478+
# Use two abstract methods
4479+
var lines =<< trim END
4480+
vim9script
4481+
abstract class A
4482+
def M1(): number
4483+
return 10
4484+
enddef
4485+
abstract def M2(): number
4486+
abstract def M3(): number
4487+
endclass
4488+
class B extends A
4489+
def M2(): number
4490+
return 20
4491+
enddef
4492+
def M3(): number
4493+
return 30
4494+
enddef
4495+
endclass
4496+
var b = B.new()
4497+
assert_equal([10, 20, 30], [b.M1(), b.M2(), b.M3()])
4498+
END
4499+
v9.CheckScriptSuccess(lines)
4500+
4501+
# Don't define an abstract method
4502+
lines =<< trim END
4503+
vim9script
4504+
abstract class A
4505+
abstract def Foo()
4506+
endclass
4507+
class B extends A
4508+
endclass
4509+
END
4510+
v9.CheckScriptFailure(lines, 'E1373: Abstract method "Foo" is not implemented')
4511+
4512+
# Use abstract method in a concrete class
4513+
lines =<< trim END
4514+
vim9script
4515+
class A
4516+
abstract def Foo()
4517+
endclass
4518+
class B extends A
4519+
endclass
4520+
END
4521+
v9.CheckScriptFailure(lines, 'E1372: Abstract method "abstract def Foo()" cannot be defined in a concrete class')
4522+
4523+
# Use abstract method in an interface
4524+
lines =<< trim END
4525+
vim9script
4526+
interface A
4527+
abstract def Foo()
4528+
endinterface
4529+
class B implements A
4530+
endclass
4531+
END
4532+
v9.CheckScriptFailure(lines, 'E1372: Abstract method "abstract def Foo()" cannot be defined in a concrete class')
4533+
4534+
# Abbreviate the "abstract" keyword
4535+
lines =<< trim END
4536+
vim9script
4537+
class A
4538+
abs def Foo()
4539+
endclass
4540+
END
4541+
v9.CheckScriptFailure(lines, 'E1065: Command cannot be shortened: abs def Foo()')
4542+
4543+
# Use "abstract" with a member variable
4544+
lines =<< trim END
4545+
vim9script
4546+
abstract class A
4547+
abstract this.val = 10
4548+
endclass
4549+
END
4550+
v9.CheckScriptFailure(lines, 'E1371: Abstract must be followed by "def" or "static"')
4551+
4552+
# Use a static abstract method
4553+
lines =<< trim END
4554+
vim9script
4555+
abstract class A
4556+
abstract static def Foo(): number
4557+
endclass
4558+
class B extends A
4559+
static def Foo(): number
4560+
return 4
4561+
enddef
4562+
endclass
4563+
assert_equal(4, B.Foo())
4564+
END
4565+
v9.CheckScriptSuccess(lines)
4566+
4567+
# Type mismatch between abstract method and concrete method
4568+
lines =<< trim END
4569+
vim9script
4570+
abstract class A
4571+
abstract def Foo(a: string, b: number): list<number>
4572+
endclass
4573+
class B extends A
4574+
def Foo(a: number, b: string): list<string>
4575+
return []
4576+
enddef
4577+
endclass
4578+
END
4579+
v9.CheckScriptFailure(lines, 'E1407: Member "Foo": type mismatch, expected func(string, number): list<number> but got func(number, string): list<string>')
4580+
4581+
# Use an abstract class to invoke an abstract method
4582+
# FIXME: This should fail
4583+
lines =<< trim END
4584+
vim9script
4585+
abstract class A
4586+
abstract static def Foo()
4587+
endclass
4588+
A.Foo()
4589+
END
4590+
v9.CheckScriptSuccess(lines)
4591+
4592+
# Invoke an abstract method from a def function
4593+
lines =<< trim END
4594+
vim9script
4595+
abstract class A
4596+
abstract def Foo(): list<number>
4597+
endclass
4598+
class B extends A
4599+
def Foo(): list<number>
4600+
return [3, 5]
4601+
enddef
4602+
endclass
4603+
def Bar(c: B)
4604+
assert_equal([3, 5], c.Foo())
4605+
enddef
4606+
var b = B.new()
4607+
Bar(b)
4608+
END
4609+
v9.CheckScriptSuccess(lines)
4610+
enddef
4611+
44764612
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/userfunc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5021,6 +5021,7 @@ define_function(
50215021
// Do not define the function when getting the body fails and when
50225022
// skipping.
50235023
if (((class_flags & CF_INTERFACE) == 0
5024+
&& (class_flags & CF_ABSTRACT_METHOD) == 0
50245025
&& get_function_body(eap, &newlines, line_arg, lines_to_free)
50255026
== FAIL)
50265027
|| eap->skip)

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ static char *(features[]) =
699699

700700
static int included_patches[] =
701701
{ /* Add new patch number below this line */
702+
/**/
703+
1885,
702704
/**/
703705
1884,
704706
/**/

src/vim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,5 +2915,6 @@ long elapsed(DWORD start_tick);
29152915
// Flags used by "class_flags" of define_function()
29162916
#define CF_CLASS 1 // inside a class
29172917
#define CF_INTERFACE 2 // inside an interface
2918+
#define CF_ABSTRACT_METHOD 4 // inside an abstract class
29182919

29192920
#endif // VIM__H

0 commit comments

Comments
 (0)