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:
Doug Kearns
2025-07-23 21:25:57 +02:00
committed by Christian Brabandt
parent 3add0d5e75
commit 72473ce9f8
35 changed files with 1197 additions and 32 deletions

View File

@ -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

View File

@ -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>>())

View 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)