runtime(vim): Update base syntax, match generic functions
Match Vim9 generic functions, added in #17313. closes: #17722 Signed-off-by: Doug Kearns <dougkearns@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
3add0d5e75
commit
72473ce9f8
@ -0,0 +1,215 @@
|
||||
vim9script
|
||||
# VIM_TEST_SETUP highlight link vim9DefTypeParam Todo
|
||||
# VIM_TEST_SETUP let g:vimsyn_folding = "f"
|
||||
# VIM_TEST_SETUP setl fdc=2 fdl=99 fdm=syntax
|
||||
# See: https://github.com/vim/vim/pull/17313#issuecomment-3046696820 (Aliaksei Budavei)
|
||||
|
||||
|
||||
# See https://github.com/vim/vim/pull/16604#issuecomment-265202845 .
|
||||
export interface Listable
|
||||
def Cons<E>(_: E): Listable
|
||||
def Reverse<E>(): Listable
|
||||
def Rest(): Listable
|
||||
def First<E>(): E
|
||||
def empty(): bool
|
||||
def len(): number
|
||||
def string(): string
|
||||
endinterface
|
||||
|
||||
enum EmptyList implements Listable
|
||||
INSTANCE
|
||||
|
||||
def Cons<E>(value: E): Listable
|
||||
return List.new<E>(value)
|
||||
enddef
|
||||
|
||||
def Reverse<E>(): Listable
|
||||
return this
|
||||
enddef
|
||||
|
||||
def Rest(): Listable
|
||||
return this
|
||||
enddef
|
||||
|
||||
def First<E>(): E
|
||||
return null
|
||||
enddef
|
||||
|
||||
def empty(): bool
|
||||
return true
|
||||
enddef
|
||||
|
||||
def len(): number
|
||||
return 0
|
||||
enddef
|
||||
|
||||
def string(): string
|
||||
return '[]'
|
||||
enddef
|
||||
endenum
|
||||
|
||||
class List implements Listable
|
||||
const _value: any
|
||||
const _size: number
|
||||
var _next: Listable
|
||||
|
||||
def new<E>(value: E)
|
||||
this._value = value
|
||||
this._size = 1
|
||||
this._next = EmptyList.INSTANCE
|
||||
enddef
|
||||
|
||||
def _newCons<E>(value: E, size: number)
|
||||
this._value = value
|
||||
this._size = size
|
||||
enddef
|
||||
|
||||
def Cons<E>(value: E): Listable
|
||||
const list: List = List._newCons<E>(value, (this._size + 1))
|
||||
list._next = this
|
||||
return list
|
||||
enddef
|
||||
|
||||
def Reverse<E>(): Listable
|
||||
var result: Listable = List.new<E>(this.First<E>())
|
||||
var list: Listable = this.Rest()
|
||||
|
||||
while !list.empty()
|
||||
result = result.Cons<E>(list.First<E>())
|
||||
list = list.Rest()
|
||||
endwhile
|
||||
|
||||
return result
|
||||
enddef
|
||||
|
||||
def Rest(): Listable
|
||||
return this._next
|
||||
enddef
|
||||
|
||||
def First<E>(): E
|
||||
return this._value
|
||||
enddef
|
||||
|
||||
def empty(): bool
|
||||
return (this._size == 0)
|
||||
enddef
|
||||
|
||||
def len(): number
|
||||
return this._size
|
||||
enddef
|
||||
|
||||
def string(): string
|
||||
if this.empty()
|
||||
return '[]'
|
||||
endif
|
||||
|
||||
var text: string = '[' .. string(this.First<any>()) .. ', '
|
||||
var list: Listable = this.Rest()
|
||||
|
||||
while !list.empty()
|
||||
text ..= string(list.First<any>()) .. ', '
|
||||
list = list.Rest()
|
||||
endwhile
|
||||
|
||||
return strpart(text, 0, (strlen(text) - 2)) .. ']'
|
||||
enddef
|
||||
endclass
|
||||
|
||||
export def MakeEmptyList(): Listable
|
||||
return EmptyList.INSTANCE
|
||||
enddef
|
||||
|
||||
export def MakeList<E>(value: E): Listable
|
||||
return List.new<E>(value)
|
||||
enddef
|
||||
|
||||
export def Map<T, U>(listable: Listable, Mapper: func(T): U): Listable
|
||||
var result: Listable = EmptyList.INSTANCE
|
||||
var list: Listable = listable
|
||||
|
||||
while !list.empty()
|
||||
result = result.Cons<U>(Mapper(list.First<T>()))
|
||||
list = list.Rest()
|
||||
endwhile
|
||||
|
||||
return result.Reverse<U>()
|
||||
enddef
|
||||
|
||||
export def Filter<T>(listable: Listable, Predicate: func(T): bool): Listable
|
||||
var result: Listable = EmptyList.INSTANCE
|
||||
var list: Listable = listable
|
||||
|
||||
while !list.empty()
|
||||
if Predicate(list.First<T>())
|
||||
result = result.Cons<T>(list.First<T>())
|
||||
endif
|
||||
|
||||
list = list.Rest()
|
||||
endwhile
|
||||
|
||||
return result.Reverse<T>()
|
||||
enddef
|
||||
|
||||
############################################################
|
||||
|
||||
echo MakeEmptyList()
|
||||
|
||||
const listX: Listable = MakeEmptyList()
|
||||
.Cons<number>(0).Cons<number>(1).Cons<number>(2).Cons<number>(3)
|
||||
const listY: Listable = MakeList<number>(0)
|
||||
.Cons<number>(1).Cons<number>(2).Cons<number>(3)
|
||||
echo listX == listY
|
||||
echo listX
|
||||
echo listX.Reverse<number>()
|
||||
echo MakeEmptyList().Reverse<any>()
|
||||
echo Filter<number>(listX, (value: number) => value % 2 != 0)
|
||||
echo Map<number, string>(listX, (value: number) => nr2char((value + 60), 1))
|
||||
|
||||
echo 4 listX.len() listY.len()
|
||||
echo listX
|
||||
echo listY
|
||||
|
||||
const list3X: Listable = listX.Rest()
|
||||
const list3Y: Listable = listY.Rest()
|
||||
echo 3 list3X.len() list3Y.len()
|
||||
echo list3X
|
||||
echo list3Y
|
||||
|
||||
const list2X: Listable = list3X.Rest()
|
||||
const list2Y: Listable = list3Y.Rest()
|
||||
echo 2 list2X.len() list2Y.len()
|
||||
echo list2X
|
||||
echo list2Y
|
||||
|
||||
const list1X: Listable = list2X.Rest()
|
||||
const list1Y: Listable = list2Y.Rest()
|
||||
echo 1 list1X.len() list1Y.len()
|
||||
echo list1X
|
||||
echo list1Y
|
||||
|
||||
const list0X: Listable = list1X.Rest()
|
||||
const list0Y: Listable = list1Y.Rest()
|
||||
echo 0 list0X.len() list0Y.len()
|
||||
echo list0X
|
||||
echo list0Y
|
||||
|
||||
const list0X_: Listable = list0X.Rest()
|
||||
const list0Y_: Listable = list0Y.Rest()
|
||||
echo 0 list0X_.len() list0Y_.len()
|
||||
echo list0X_
|
||||
echo list0Y_
|
||||
|
||||
const list0X__: Listable = list0X_.Rest()
|
||||
const list0Y__: Listable = list0Y_.Rest()
|
||||
echo 0 list0X__.len() list0Y__.len()
|
||||
echo list0X__
|
||||
echo list0Y__
|
||||
|
||||
|
||||
const listZ: Listable = MakeList<Listable>(MakeList<number>(-1))
|
||||
const listZZ: Listable = listZ.Cons<Listable>(MakeList<number>(0))
|
||||
.Cons<Listable>(MakeList<number>(1))
|
||||
.Cons<Listable>(MakeList<number>(2))
|
||||
.Cons<Listable>(MakeList<number>(3))
|
||||
echo listZZ
|
||||
|
||||
@ -0,0 +1,177 @@
|
||||
vim9script
|
||||
# VIM_TEST_SETUP highlight link vim9DefTypeParam Todo
|
||||
# VIM_TEST_SETUP let g:vimsyn_folding = "f"
|
||||
# VIM_TEST_SETUP setl fdc=2 fdl=99 fdm=syntax
|
||||
# See: https://github.com/vim/vim/pull/17313#issuecomment-3046696820 (Aliaksei Budavei)
|
||||
|
||||
# See https://github.com/vim/vim/issues/14330#issuecomment-2028938515 .
|
||||
export class Set
|
||||
final _elements: dict<number>
|
||||
const _Mapper: func(number, string): any
|
||||
const ToStringer: func(any): string
|
||||
const FromStringer: func(string): any
|
||||
|
||||
static def _Mapper<E>(F: func(string): E): func(number, string): E
|
||||
return ((G: func(string): E) => (_: number, v: string): E => G(v))(F)
|
||||
enddef
|
||||
|
||||
def new<E>()
|
||||
this._elements = {}
|
||||
this._Mapper = _Mapper<E>((s: string): E => eval(s))
|
||||
this.ToStringer = (a: E): string => string(a)
|
||||
this.FromStringer = (s: string): E => eval(s)
|
||||
enddef
|
||||
|
||||
def newFromList<E>(elements: list<E>, ToStringer: func(E): string,
|
||||
FromStringer: func(string): E)
|
||||
this._elements = elements
|
||||
->reduce(((F: func(E): string) => (d: dict<number>, v: E) =>
|
||||
extend({[F(v)]: 1}, d))(ToStringer),
|
||||
{})
|
||||
this._Mapper = _Mapper<E>(FromStringer)
|
||||
this.ToStringer = ToStringer
|
||||
this.FromStringer = FromStringer
|
||||
enddef
|
||||
|
||||
def _FromList<E>(elements: list<E>): Set
|
||||
return Set.newFromList<E>(elements, this.ToStringer, this.FromStringer)
|
||||
enddef
|
||||
|
||||
def Contains<E>(element: E): bool
|
||||
return has_key(this._elements, this.ToStringer(element))
|
||||
enddef
|
||||
|
||||
def Elements<E>(): list<E>
|
||||
return keys(this._elements)->mapnew(this._Mapper)
|
||||
enddef
|
||||
|
||||
def empty(): bool
|
||||
return empty(this._elements)
|
||||
enddef
|
||||
|
||||
def len(): number
|
||||
return len(this._elements)
|
||||
enddef
|
||||
|
||||
def string(): string
|
||||
return string(keys(this._elements))
|
||||
enddef
|
||||
|
||||
# {1, 2, 3} ⊇ {1, 2}.
|
||||
def Superset(that: Set): bool
|
||||
return (len(this._elements) >= len(that._elements)) && that._elements
|
||||
->keys()
|
||||
->indexof(((set: Set) => (_: number, v: string) => !set._elements
|
||||
->has_key(v))(this)) < 0
|
||||
enddef
|
||||
|
||||
# {1, 2} ⊆ {1, 2, 3}.
|
||||
def Subset(that: Set): bool
|
||||
return (len(this._elements) <= len(that._elements)) && this._elements
|
||||
->keys()
|
||||
->indexof(((set: Set) => (_: number, v: string) => !set._elements
|
||||
->has_key(v))(that)) < 0
|
||||
enddef
|
||||
|
||||
# {1, 2, 3} ∪ {2, 3, 4} = {1, 2, 3, 4}.
|
||||
def Union(that: Set): Set
|
||||
return this._FromList<any>({}
|
||||
->extend(that._elements)
|
||||
->extend(this._elements)
|
||||
->keys()
|
||||
->map(this._Mapper))
|
||||
enddef
|
||||
|
||||
# {1, 2, 3} ∩ {2, 3, 4} = {2, 3}.
|
||||
def Intersection(that: Set): Set
|
||||
return this._FromList<any>(this._elements
|
||||
->keys()
|
||||
->filter(((set: Set) => (_: number, v: string) => set._elements
|
||||
->has_key(v))(that))
|
||||
->map(this._Mapper))
|
||||
enddef
|
||||
|
||||
# {1, 2, 3} \ {2, 3, 4} = {1}.
|
||||
# {2, 3, 4} \ {1, 2, 3} = {4}.
|
||||
def SetDifference(that: Set): Set
|
||||
return this._FromList<any>(this._elements
|
||||
->keys()
|
||||
->filter(((set: Set) => (_: number, v: string) => !set._elements
|
||||
->has_key(v))(that))
|
||||
->map(this._Mapper))
|
||||
enddef
|
||||
|
||||
# {1, 2, 3} △ {2, 3, 4} = {1, 4}.
|
||||
def SymmetricDifference(that: Set): Set
|
||||
return this.Union(that).SetDifference(this.Intersection(that))
|
||||
enddef
|
||||
endclass
|
||||
|
||||
############################################################
|
||||
|
||||
const ToStr: func(number): string = (s: number) => string(s)
|
||||
const FromStr: func(string): number = (s: string) => str2nr(s)
|
||||
|
||||
echo Set.newFromList<number>([1, 2, 3], ToStr, FromStr)
|
||||
.Subset(Set.newFromList<number>([1, 2], ToStr, FromStr))
|
||||
echo Set.newFromList<number>([1, 2], ToStr, FromStr)
|
||||
.Subset(Set.newFromList<number>([1, 2, 3], ToStr, FromStr))
|
||||
echo Set.newFromList<number>([1, 2], ToStr, FromStr)
|
||||
.Superset(Set.newFromList<number>([1, 2, 3], ToStr, FromStr))
|
||||
echo Set.newFromList<number>([1, 2, 3], ToStr, FromStr)
|
||||
.Superset(Set.newFromList<number>([1, 2], ToStr, FromStr))
|
||||
|
||||
echo Set.newFromList<number>([1, 2, 3], ToStr, FromStr)
|
||||
.Union(Set.newFromList<number>([2, 3, 4], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
echo Set.newFromList<number>([2, 3, 4], ToStr, FromStr)
|
||||
.Union(Set.newFromList<number>([1, 2, 3], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
|
||||
echo Set.newFromList<number>([1, 2, 3], ToStr, FromStr)
|
||||
.Intersection(Set.newFromList<number>([2, 3, 4], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
echo Set.newFromList<number>([2, 3, 4], ToStr, FromStr)
|
||||
.Intersection(Set.newFromList<number>([1, 2, 3], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
|
||||
echo Set.newFromList<number>([1, 2, 3], ToStr, FromStr)
|
||||
.SetDifference(Set.newFromList<number>([2, 3, 4], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
echo Set.newFromList<number>([2, 3, 4], ToStr, FromStr)
|
||||
.SetDifference(Set.newFromList<number>([1, 2, 3], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
|
||||
echo Set.newFromList<number>([1, 2, 3], ToStr, FromStr)
|
||||
.SymmetricDifference(Set.newFromList<number>([2, 3, 4], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
echo Set.newFromList<number>([2, 3, 4], ToStr, FromStr)
|
||||
.SymmetricDifference(Set.newFromList<number>([1, 2, 3], ToStr, FromStr))
|
||||
.Elements<number>()
|
||||
|
||||
############################################################
|
||||
|
||||
const none: Set = Set.new<any>()
|
||||
echo none.len()
|
||||
echo none.empty()
|
||||
echo none.string()
|
||||
echo string(none.Elements<any>())
|
||||
|
||||
const sets: Set = Set.newFromList<Set>(
|
||||
[Set.new<any>(), Set.new<any>(), Set.new<any>(), Set.new<any>()],
|
||||
(o: Set): string => string(o),
|
||||
(_: string): Set => Set.new<any>())
|
||||
echo sets.len()
|
||||
echo sets.empty()
|
||||
echo sets.string()
|
||||
echo string(sets.Elements<Set>())
|
||||
|
||||
const lists: Set = Set.newFromList<list<any>>(
|
||||
[[[[[]]]]],
|
||||
(o: list<any>): string => string(o),
|
||||
(s: string): list<any> => eval(s))
|
||||
echo lists.len()
|
||||
echo lists.empty()
|
||||
echo lists.string()
|
||||
echo string(lists.Elements<list<any>>())
|
||||
|
||||
97
runtime/syntax/testdir/input/vim9_generic_functions.vim
Normal file
97
runtime/syntax/testdir/input/vim9_generic_functions.vim
Normal file
@ -0,0 +1,97 @@
|
||||
vim9script
|
||||
# Vim9 generic functions
|
||||
# VIM_TEST_SETUP highlight link vim9DefTypeParam Todo
|
||||
# VIM_TEST_SETUP let g:vimsyn_folding = "f"
|
||||
# VIM_TEST_SETUP setl fdc=2 fdl=99 fdm=syntax
|
||||
|
||||
|
||||
# :help generic-functions
|
||||
|
||||
def MyFunc<T, A, B>(param1: T): T
|
||||
var f: A
|
||||
var x = param1
|
||||
return x
|
||||
enddef
|
||||
|
||||
MyFunc<number, string, list<number>>()
|
||||
|
||||
|
||||
def Flatten<T>(x: list<list<T>>): list<T>
|
||||
var result: list<T> = []
|
||||
for inner in x
|
||||
result += inner
|
||||
endfor
|
||||
return result
|
||||
enddef
|
||||
|
||||
echo Flatten<number>([[1, 2], [3]])
|
||||
|
||||
|
||||
class A
|
||||
def Foo<X, Y>()
|
||||
enddef
|
||||
endclass
|
||||
var a = A.new()
|
||||
a.Foo<number, string>()
|
||||
|
||||
|
||||
def MakeEcho<T>(): func(T): T
|
||||
return (x: T): T => x
|
||||
enddef
|
||||
|
||||
var EchoNumber = MakeEcho<number>()
|
||||
echo EchoNumber(123)
|
||||
|
||||
var EchoString = MakeEcho<string>()
|
||||
echo EchoString('abc')
|
||||
|
||||
# FIXME: add specific command handling
|
||||
# defcompile MyFunc<number, list<number>, dict<string>>
|
||||
|
||||
# disassemble MyFunc<string, dict<string>>
|
||||
# disassemble MyFunc<number, list<blob>>
|
||||
|
||||
|
||||
# funcrefs
|
||||
|
||||
var Foo = Bar<number>
|
||||
Execute(Bar<number>)
|
||||
|
||||
var Foo = bar.Baz<string>
|
||||
Execute(bar.Baz<string>)
|
||||
|
||||
class Foo
|
||||
def _MethodA<T>(arg: T)
|
||||
echo arg
|
||||
enddef
|
||||
def MethodB()
|
||||
var F = this._MethodA<number>
|
||||
F("text")
|
||||
enddef
|
||||
endclass
|
||||
|
||||
class Bar extends Foo
|
||||
def MethodC()
|
||||
var F = super._MethodA<number>
|
||||
F("text")
|
||||
enddef
|
||||
endclass
|
||||
|
||||
|
||||
# Issue: https://github.com/vim/vim/pull/17722#issuecomment-3075531052
|
||||
|
||||
export def Id<U>(): func(U): U
|
||||
return (X_: U) => X_
|
||||
enddef
|
||||
|
||||
export def Const<U, V>(): func(U): func(V): U
|
||||
return (X_: U) => (_: V) => X_
|
||||
enddef
|
||||
|
||||
export def Flip<U, V, W>(): func(func(U): func(V): W): func(V): func(U): W
|
||||
return (F_: func(U): func(V): W) => (Y_: V) => (X_: U) => F_(X_)(Y_)
|
||||
enddef
|
||||
|
||||
echo Const<number, any>()(2)(null)
|
||||
== Flip<number, any, number>()(Const<number, any>())(null)(2)
|
||||
|
||||
Reference in New Issue
Block a user