Expression evaluation
Translations of this material:
- into English: Перевод "Expression evaluation". private, Translation is not started yet.
-
Submitted for translation by anya 20.09.2011
- into Ukrainian: Перевод "Expression evaluation". Translation is not started yet.
-
Submitted for translation by Danteee 08.09.2011
- into Russian: Berenika. 0% translated in draft.
-
Submitted for translation by Dmitry.Minsky 30.08.2009
Published 2 years, 7 months ago.
Text
*eval.txt* For Vim version 7.2. Last change: 2008 Aug 09
VIM REFERENCE MANUAL by Bram Moolenaar
Expression evaluation *expression* *expr* *E15* *eval*
Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|.
Note: Expression evaluation can be disabled at compile time. If this has been
done, the features in this document are not available. See |+eval| and
|no-eval-feature|.
1. Variables |variables|
1.1 Variable types
1.2 Function references |Funcref|
1.3 Lists |Lists|
1.4 Dictionaries |Dictionaries|
1.5 More about variables |more-variables|
2. Expression syntax |expression-syntax|
3. Internal variable |internal-variables|
4. Builtin Functions |functions|
5. Defining functions |user-functions|
6. Curly braces names |curly-braces-names|
7. Commands |expression-commands|
8. Exception handling |exception-handling|
9. Examples |eval-examples|
10. No +eval feature |no-eval-feature|
11. The sandbox |eval-sandbox|
12. Textlock |textlock|
{Vi does not have any of these commands}
==============================================================================
1. Variables *variables*
1.1 Variable types ~
*E712*
There are six types of variables:
Number A 32 bit signed number. |expr-number| *Number*
Examples: -123 0x10 0177
Float A floating point number. |floating-point-format| *Float*
{only when compiled with the |+float| feature}
Examples: 123.456 1.15e-6 -1.1e3
String A NUL terminated string of 8-bit unsigned characters (bytes).
|expr-string| Examples: "ab\txx\"--" 'x-z''a,c'
Funcref A reference to a function |Funcref|.
Example: function("strlen")
List An ordered sequence of items |List|.
Example: [1, 2, ['a', 'b']]
Dictionary An associative, unordered array: Each entry has a key and a
value. |Dictionary|
Example: {'blue': "#0000ff", 'red': "#ff0000"}
The Number and String types are converted automatically, depending on how they
are used.
Conversion from a Number to a String is by making the ASCII representation of
the Number. Examples: >
Number 123 --> String "123"
Number 0 --> String "0"
Number -1 --> String "-1"
Conversion from a String to a Number is done by converting the first digits
to a number. Hexadecimal "0xf9" and Octal "017" numbers are recognized. If
the String doesn't start with digits, the result is zero. Examples: >
String "456" --> Number 456
String "6bar" --> Number 6
String "foo" --> Number 0
String "0xf1" --> Number 241
String "0100" --> Number 64
String "-8" --> Number -8
String "+8" --> Number 0
To force conversion from String to Number, add zero to it: >
:echo "0100" + 0
< 64 ~
To avoid a leading zero to cause octal conversion, or for using a different
base, use |str2nr()|.
For boolean operators Numbers are used. Zero is FALSE, non-zero is TRUE.
Note that in the command >
:if "foo"
"foo" is converted to 0, which means FALSE. To test for a non-empty string,
use strlen(): >
:if strlen("foo")
< *E745* *E728* *E703* *E729* *E730* *E731*
List, Dictionary and Funcref types are not automatically converted.
*E805* *E806* *E808*
When mixing Number and Float the Number is converted to Float. Otherwise
there is no automatic conversion of Float. You can use str2float() for String
to Float, printf() for Float to String and float2nr() for Float to Number.
*E706* *sticky-type-checking*
You will get an error if you try to change the type of a variable. You need
to |:unlet| it first to avoid this error. String and Number are considered
equivalent though, as well are Float and Number. Consider this sequence of
commands: >
:let l = "string"
:let l = 44 " changes type from String to Number
:let l = [1, 2, 3] " error! l is still a Number
:let l = 4.4 " changes type from Number to Float
:let l = "string" " error!
1.2 Function references ~
*Funcref* *E695* *E718*
A Funcref variable is obtained with the |function()| function. It can be used
in an expression in the place of a function name, before the parenthesis
around the arguments, to invoke the function it refers to. Example: >
:let Fn = function("MyFunc")
:echo Fn()
< *E704* *E705* *E707*
A Funcref variable must start with a capital, "s:", "w:", "t:" or "b:". You
cannot have both a Funcref variable and a function with the same name.
A special case is defining a function and directly assigning its Funcref to a
Dictionary entry. Example: >
:function dict.init() dict
: let self.val = 0
:endfunction
The key of the Dictionary can start with a lower case letter. The actual
function name is not used here. Also see |numbered-function|.
A Funcref can also be used with the |:call| command: >
:call Fn()
:call dict.init()
The name of the referenced function can be obtained with |string()|. >
:let func = string(Fn)
You can use |call()| to invoke a Funcref and use a list variable for the
arguments: >
:let r = call(Fn, mylist)
1.3 Lists ~
*List* *Lists* *E686*
A List is an ordered sequence of items. An item can be of any type. Items
can be accessed by their index number. Items can be added and removed at any
position in the sequence.
List creation ~
*E696* *E697*
A List is created with a comma separated list of items in square brackets.
Examples: >
:let mylist = [1, two, 3, "four"]
:let emptylist = []
An item can be any expression. Using a List for an item creates a
List of Lists: >
:let nestlist = [[11, 12], [21, 22], [31, 32]]
An extra comma after the last item is ignored.
List index ~
*list-index* *E684*
An item in the List can be accessed by putting the index in square brackets
after the List. Indexes are zero-based, thus the first item has index zero. >
:let item = mylist[0] " get the first item: 1
:let item = mylist[2] " get the third item: 3
When the resulting item is a list this can be repeated: >
:let item = nestlist[0][1] " get the first list, second item: 12
<
A negative index is counted from the end. Index -1 refers to the last item in
the List, -2 to the last but one item, etc. >
:let last = mylist[-1] " get the last item: "four"
To avoid an error for an invalid index use the |get()| function. When an item
is not available it returns zero or the default value you specify: >
:echo get(mylist, idx)
:echo get(mylist, idx, "NONE")
List concatenation ~
Two lists can be concatenated with the "+" operator: >
:let longlist = mylist + [5, 6]
:let mylist += [7, 8]
To prepend or append an item turn the item into a list by putting [] around
it. To change a list in-place see |list-modification| below.
Sublist ~
A part of the List can be obtained by specifying the first and last index,
separated by a colon in square brackets: >
:let shortlist = mylist[2:-1] " get List [3, "four"]
Omitting the first index is similar to zero. Omitting the last index is
similar to -1. >
:let endlist = mylist[2:] " from item 2 to the end: [3, "four"]
:let shortlist = mylist[2:2] " List with one item: [3]
:let otherlist = mylist[:] " make a copy of the List
If the first index is beyond the last item of the List or the second item is
before the first item, the result is an empty list. There is no error
message.
If the second index is equal to or greater than the length of the list the
length minus one is used: >
:let mylist = [0, 1, 2, 3]
:echo mylist[2:8] " result: [2, 3]
NOTE: mylist[s:e] means using the variable "s:e" as index. Watch out for
using a single letter variable before the ":". Insert a space when needed:
mylist[s : e].
List identity ~
*list-identity*
When variable "aa" is a list and you assign it to another variable "bb", both
variables refer to the same list. Thus changing the list "aa" will also
change "bb": >
:let aa = [1, 2, 3]
:let bb = aa
:call add(aa, 4)
:echo bb
< [1, 2, 3, 4]
Making a copy of a list is done with the |copy()| function. Using [:] also
works, as explained above. This creates a shallow copy of the list: Changing
a list item in the list will also change the item in the copied list: >
:let aa = [[1, 'a'], 2, 3]
:let bb = copy(aa)
:call add(aa, 4)
:let aa[0][1] = 'aaa'
:echo aa
< [[1, aaa], 2, 3, 4] >
:echo bb
< [[1, aaa], 2, 3]
To make a completely independent list use |deepcopy()|. This also makes a
copy of the values in the list, recursively. Up to a hundred levels deep.
The operator "is" can be used to check if two variables refer to the same
List. "isnot" does the opposite. In contrast "==" compares if two lists have
the same value. >
:let alist = [1, 2, 3]
:let blist = [1, 2, 3]
:echo alist is blist
< 0 >
:echo alist == blist
< 1
Note about comparing lists: Two lists are considered equal if they have the
same length and all items compare equal, as with using "==". There is one
exception: When comparing a number with a string they are considered
different. There is no automatic type conversion, as with using "==" on
variables. Example: >
echo 4 == "4"
< 1 >
echo [4] == ["4"]
< 0
Thus comparing Lists is more strict than comparing numbers and strings. You
can compare simple values this way too by putting them in a list: >
:let a = 5
:let b = "5"
:echo a == b
< 1 >
:echo [a] == [b]
< 0
List unpack ~
To unpack the items in a list to individual variables, put the variables in
square brackets, like list items: >
:let [var1, var2] = mylist
When the number of variables does not match the number of items in the list
this produces an error. To handle any extra items from the list append ";"
and a variable name: >
:let [var1, var2; rest] = mylist
This works like: >
:let var1 = mylist[0]
:let var2 = mylist[1]
:let rest = mylist[2:]
Except that there is no error if there are only two items. "rest" will be an
empty list then.
List modification ~
*list-modification*
To change a specific item of a list use |:let| this way: >
:let list[4] = "four"
:let listlist[0][3] = item
To change part of a list you can specify the first and last item to be
modified. The value must at least have the number of items in the range: >
:let list[3:5] = [3, 4, 5]
Adding and removing items from a list is done with functions. Here are a few
examples: >
:call insert(list, 'a') " prepend item 'a'
:call insert(list, 'a', 3) " insert item 'a' before list[3]
:call add(list, "new") " append String item
:call add(list, [1, 2]) " append a List as one new item
:call extend(list, [1, 2]) " extend the list with two more items
:let i = remove(list, 3) " remove item 3
:unlet list[3] " idem
:let l = remove(list, 3, -1) " remove items 3 to last item
:unlet list[3 : ] " idem
:call filter(list, 'v:val !~ "x"') " remove items with an 'x'
Changing the order of items in a list: >
:call sort(list) " sort a list alphabetically
:call reverse(list) " reverse the order of items
For loop ~
The |:for| loop executes commands for each item in a list. A variable is set
to each item in the list in sequence. Example: >
:for item in mylist
: call Doit(item)
:endfor
This works like: >
:let index = 0
:while index < len(mylist)
: let item = mylist[index]
: :call Doit(item)
: let index = index + 1
:endwhile
Note that all items in the list should be of the same type, otherwise this
results in error |E706|. To avoid this |:unlet| the variable at the end of
the loop.
If all you want to do is modify each item in the list then the |map()|
function will be a simpler method than a for loop.
Just like the |:let| command, |:for| also accepts a list of variables. This
requires the argument to be a list of lists. >
:for [lnum, col] in [[1, 3], [2, 8], [3, 0]]
: call Doit(lnum, col)
:endfor
This works like a |:let| command is done for each list item. Again, the types
must remain the same to avoid an error.
It is also possible to put remaining items in a List variable: >
:for [i, j; rest] in listlist
: call Doit(i, j)
: if !empty(rest)
: echo "remainder: " . string(rest)
: endif
:endfor
List functions ~
*E714*
Functions that are useful with a List: >
:let r = call(funcname, list) " call a function with an argument list
:if empty(list) " check if list is empty
:let l = len(list) " number of items in list
:let big = max(list) " maximum value in list
:let small = min(list) " minimum value in list
:let xs = count(list, 'x') " count nr of times 'x' appears in list
:let i = index(list, 'x') " index of first 'x' in list
:let lines = getline(1, 10) " get ten text lines from buffer
:call append('$', lines) " append text lines in buffer
:let list = split("a b c") " create list from items in a string
:let string = join(list, ', ') " create string from list items
:let s = string(list) " String representation of list
:call map(list, '">> " . v:val') " prepend ">> " to each item
Don't forget that a combination of features can make things simple. For
example, to add up all the numbers in a list: >
:exe 'let sum = ' . join(nrlist, '+')
1.4 Dictionaries ~
*Dictionaries* *Dictionary*
A Dictionary is an associative array: Each entry has a key and a value. The
entry can be located with the key. The entries are stored without a specific
ordering.
Dictionary creation ~
*E720* *E721* *E722* *E723*
A Dictionary is created with a comma separated list of entries in curly
braces. Each entry has a key and a value, separated by a colon. Each key can
only appear once. Examples: >
:let mydict = {1: 'one', 2: 'two', 3: 'three'}
:let emptydict = {}
< *E713* *E716* *E717*
A key is always a String. You can use a Number, it will be converted to a
String automatically. Thus the String '4' and the number 4 will find the same
entry. Note that the String '04' and the Number 04 are different, since the
Number will be converted to the String '4'.
A value can be any expression. Using a Dictionary for a value creates a
nested Dictionary: >
:let nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}}
An extra comma after the last entry is ignored.
Accessing entries ~
The normal way to access an entry is by putting the key in square brackets: >
:let val = mydict["one"]
:let mydict["four"] = 4
You can add new entries to an existing Dictionary this way, unlike Lists.
For keys that consist entirely of letters, digits and underscore the following
form can be used |expr-entry|: >
:let val = mydict.one
:let mydict.four = 4
Since an entry can be any type, also a List and a Dictionary, the indexing and
key lookup can be repeated: >
:echo dict.key[idx].key
Dictionary to List conversion ~
You may want to loop over the entries in a dictionary. For this you need to
turn the Dictionary into a List and pass it to |:for|.
Most often you want to loop over the keys, using the |keys()| function: >
:for key in keys(mydict)
: echo key . ': ' . mydict[key]
:endfor
The List of keys is unsorted. You may want to sort them first: >
:for key in sort(keys(mydict))
To loop over the values use the |values()| function: >
:for v in values(mydict)
: echo "value: " . v
:endfor
If you want both the key and the value use the |items()| function. It returns
a List in which each item is a List with two items, the key and the value: >
:for [key, value] in items(mydict)
: echo key . ': ' . value
:endfor
Dictionary identity ~
*dict-identity*
Just like Lists you need to use |copy()| and |deepcopy()| to make a copy of a
Dictionary. Otherwise, assignment results in referring to the same
Dictionary: >
:let onedict = {'a': 1, 'b': 2}
:let adict = onedict
:let adict['a'] = 11
:echo onedict['a']
11
Two Dictionaries compare equal if all the key-value pairs compare equal. For
more info see |list-identity|.
Dictionary modification ~
*dict-modification*
To change an already existing entry of a Dictionary, or to add a new entry,
use |:let| this way: >
:let dict[4] = "four"
:let dict['one'] = item
Removing an entry from a Dictionary is done with |remove()| or |:unlet|.
Three ways to remove the entry with key "aaa" from dict: >
:let i = remove(dict, 'aaa')
:unlet dict.aaa
:unlet dict['aaa']
Merging a Dictionary with another is done with |extend()|: >
:call extend(adict, bdict)
This extends adict with all entries from bdict. Duplicate keys cause entries
in adict to be overwritten. An optional third argument can change this.
Note that the order of entries in a Dictionary is irrelevant, thus don't
expect ":echo adict" to show the items from bdict after the older entries in
adict.
Weeding out entries from a Dictionary can be done with |filter()|: >
:call filter(dict, 'v:val =~ "x"')
This removes all entries from "dict" with a value not matching 'x'.
Dictionary function ~
*Dictionary-function* *self* *E725*
When a function is defined with the "dict" attribute it can be used in a
special way with a dictionary. Example: >
:function Mylen() dict
: return len(self.data)
:endfunction
:let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
:echo mydict.len()
This is like a method in object oriented programming. The entry in the
Dictionary is a |Funcref|. The local variable "self" refers to the dictionary
the function was invoked from.
It is also possible to add a function without the "dict" attribute as a
Funcref to a Dictionary, but the "self" variable is not available then.
*numbered-function* *anonymous-function*
To avoid the extra name for the function it can be defined and directly
assigned to a Dictionary in this way: >
:let mydict = {'data': [0, 1, 2, 3]}
:function mydict.len() dict
: return len(self.data)
:endfunction
:echo mydict.len()
The function will then get a number and the value of dict.len is a |Funcref|
that references this function. The function can only be used through a
|Funcref|. It will automatically be deleted when there is no |Funcref|
remaining that refers to it.
It is not necessary to use the "dict" attribute for a numbered function.
