Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
KLELLANG(1)			    libklel			   KLELLANG(1)

       This manual page	documents the language as understood by	the KL-EL
       library.	 For documentation on how to embed the KL-EL compiler and
       interpreter in an application, see klelapi(3).  For a tutorial on how
       to use the library, see kleltut(3).

       The language understood by KL-EL	is an expression language.  Everything
       in the language is an expression	that has a value.  The purpose of the
       library is to allow these expressions to	be input at runtime and	have
       the application make use	of the resulting values	in some	fashion.

       There are two kinds of KL-EL expressions: value expressions (often
       referred	to as simply "expressions") and	guarded	commands.  Guarded
       commands	are more complicated, but they are also	very useful in certain
       situations.  Because guarded commands are more complex than value
       expressions, they will be covered second.

       Expressions in KL-EL are	not sensitive to whitespace; whitespace	is
       only significant	inside literal strings.

       Every value in KL-EL has	one and	only one type, and the type of a given
       expression never	changes.  That makes KL-EL strongly typed, and this
       typing discipline is possibly its most interesting feature.  KL-EL was
       designed	to be useful in	applications where an expression is compiled
       only once but executed thousands	or millions of times with different
       parameters, and possibly	on ephemeral or	forensic data.	If
       typechecking were not performed until evaluation, it is possible	that a
       failure could occur after millions of executions	on some	set of inputs,
       rendering the entire run	(or a large portion of it) invalid.  In	the
       best case, the expression could be fixed	and execution could pick up
       where it	left off, but in the worst case, it may	be impossible to
       recover the values used previously or begin execution again.  Checking
       types at	compile	time also makes	things faster for multiple executions
       of a given expression, since types do not need to be checked on each

       KL-EL understands four types:

       Booleans	(either	true or	false)
       Integers	(signed	64-bit)
       Reals (IEEE double-precision floating point)
       Strings (sequences of bytes with	no length limitations, embedded	NULL
       bytes are allowed)

       Functions are provided to transform values of one type to another type
       as necessary.  In general, there	is no concept of type promotion.
       Expressions like

	   "123" + 5

       don't work since	addition is not	defined	for strings.  There is a
       slight relaxation of this restriction for expressions involving a
       mixture of integers and reals --	integers are silently promoted to real
       values when they	are used in arithmetic expressions involving reals.
       This is the only	exception to the typing	discipline.  Note that the
       exception only applies to arithmetic expressions	-- functions expecting
       real arguments will not accept integer arguments.

       Any top-level expression	can be named, and this name can	be extracted
       from the	compiled expression at runtime.	 This is useful	in situations
       where there may be many unrelated expressions (say, in a	configuration
       file), and it would be useful to	identify expressions in	diagnostics or
       other output.

       To name an expression, simply prefix it with a name and a colon.	 A
       name in this case may consist of	letters, numbers, and underscores, and
       must begin with a letter.  For example, this gives an expression	"1 +
       1" the name "Example":

	 Example : 1 + 1

       Once again, note	that only top-level expressions	may be named.

       Value expressions are simple expressions	that, when evaluated, produce
       a value.	 There are seven different kinds of value expressions:

       Function	calls
       Unary (arithmetic negation, logical negation, bitwise negation)
       Binary (arithmetic, string concatenation, comparison)
       Ternary (conditional evaluation)
       Let (lexical scoping)

       Each of these expression	types is covered below.	 For more information
       on how to retrieve the value of an evaluated expression using the
       library,	see klelapi(3).

       There is	no literal syntax for Boolean values.  The standard variables
       "true" and "false" are defined and have their expected meanings.

       Numbers can be written in octal,	decimal, or hexadecimal.  Octal
       numbers are prefixed with '0o', and hexadecimal numbers are prefixed
       with '0x'.  Sequences of	decimal	digits with no prefix are assumed to
       be in decimal.

       Real numbers are	written	in decimal, with '.' as	the decimal point.
       The decimal point and one digit after it	are obligatory.	 An optional
       exponent	can be provided	by suffixing the number	with 'e', an optional
       minus sign (indicating a	negative exponent), and	at least one decimal

       Literal strings are written enclosed in double quotes.  Any character
       may appear between the double quotes except for newlines, double
       quotes, backslashes, percent signs, and literal zeros (NULL bytes).  By
       using escapes, these and	other characters can be	conveniently inserted.
       The following escapes are defined:

       \\ (backslash)
       \" (double quote)
       \r (carriage return)
       \n (linefeed)
       \% (percent sign)
       \xHH (the byte whose value is HH	in hexadecimal)

       Literal strings may also	contain	interpolations.	 Interpolations	are of
       one of the forms



       It is because of	this syntax that percent signs are recognized as an
       escapable character.  Interpolations take the value of the named
       variable, convert that value to a string, and embed the stringified
       value into the string produced by evaluating the	string literal.
       Variable	names enclosed in curly	brackets have their value inserted as
       is, while those enclosed	in parentheses have their values inserted
       after any special characters have been quoted (this is referred to as a
       quoted interpolation).  In this case "special characters" and the
       character used to quote them are	defined	by the application using the
       library,	with sensible defaults.

       Variables can be	used anywhere where an expression is expected.
       Variables are of	static type, but their values may change at any	time.
       Variables are either exported from the application using	the library
       (referred to as the "host" or "host application"), or they are
       introduced by a let expression (see below).  Applications using the
       library can export any number of	variables into the KL-EL environment,
       allowing	for simple interaction between the host	application and	KL-EL.
       For information on how applications export variables into the KL-EL
       environment, see	klelapi(3).

       KL-EL comes with	a standard library that	defines	several	variables.
       New variables can be introduced inside an expression by introducing a
       new scope using a let expression; these expressions are discussed

       It is not possible to define a function in KL-EL, but the application
       using the library can export as many functions as it needs.  KL-EL also
       comes with a standard library of	functions.  The	functions in this
       library are automatically available for use in any expression unless
       specifically disallowed by the host application.

       A function call uses syntax familiar from C:

	   name(arg0, arg1, ...	argN)

       Due to the way types are	represented in the type	checker, functions are
       limited to thirteen arguments.  It is important to note that functions
       are not first-class values; they	can neither be passed as arguments to
       nor returned as the result of other functions.

       For more	information on how to export a function	into the KL-EL
       environment, see	klelapi(3).

       Below three (3) unary operators are defined in terms of their operator
       symbol, operand type, and result	type.  The type	codes B, I, and	R
       represent boolean, integer, and real types, respectively.

			      ======= DEFINITION =======
				      o	 l  r  r
				      p	 e  i  e
				      e	 f  g  s
				      r	 t  h  u
				      a	 t  t  l
				      t	       t
	  ======  OPERATION  ===========================
	  Arithmetic Negation	      -	    I  I
	  Arithmetic Negation	      -	    R  R
	  Bitwise NOT		      ~	    I  I
	  Boolean Negation	      !	    B  B

       Note that unary operators bind more tightly than	any binary operator.

       Below twenty-one	(21) binary operators are defined in terms of their
       operator	symbol,	operand	types, and result type.	 These operators are
       listed in decreasing order of precedence.  The type codes B, I, R, and
       S represent boolean, integer, real, and string types, respectively.

			      ======= DEFINITION =======
				      o	 l  r  r
				      p	 e  i  e
				      e	 f  g  s
				      r	 t  h  u
				      a	 t  t  l
				      t	       t
	  ======  OPERATION  ===========================
	  Multiplication	      *	 I  I  I
	  Multiplication	      *	 R  I  R
	  Multiplication	      *	 I  R  R
	  Multiplication	      *	 R  R  R
	  Division		      /	 I  I  I
	  Division		      /	 R  I  R
	  Division		      /	 I  R  R
	  Division		      /	 R  R  R
	  Modular Division	      %	 I  I  I
	  Logical Conjunction	     &&	 B  B  B
	  Bitwise Roll Left	     <<	 I  I  I
	  Bitwise Roll Right	     >>	 I  I  I
	  String Concatenation	      .	 S  S  S
	  Addition		      +	 I  I  I
	  Addition		      +	 R  I  R
	  Addition		      +	 I  R  R
	  Addition		      +	 R  R  R
	  Subtraction		      -	 I  I  I
	  Subtraction		      -	 R  I  R
	  Subtraction		      -	 I  R  R
	  Subtraction		      -	 R  R  R
	  Logical Disjunction	     ||	 B  B  B
	  Bitwise AND		      &	 I  I  I
	  Bitwise XOR		      ^	 I  I  I
	  Bitwise OR		      |	 I  I  I
	  Less than		      <	 I  I  B
	  Less than		      <	 R  R  B
	  Less than		      <	 S  S  B
	  Greater than		      >	 I  I  B
	  Greater than		      >	 R  R  B
	  Greater than		      >	 S  S  B
	  Less than or equal	     <=	 I  I  B
	  Less than or equal	     <=	 R  R  B
	  Less than or equal	     <=	 S  S  B
	  Greater than or equal	     >=	 I  I  B
	  Greater than or equal	     >=	 R  R  B
	  Greater than or equal	     >=	 S  S  B
	  Equal			     ==	 B  B  B
	  Equal			     ==	 I  I  B
	  Equal			     ==	 R  R  B
	  Equal			     ==	 S  S  B
	  Not equal		     !=	 B  B  B
	  Not equal		     !=	 I  I  B
	  Not equal		     !=	 R  R  B
	  Not equal		     !=	 S  S  B
	  Regex	match		     =~	 S  S  B
	  Regex	non-match	     !~	 S  S  B

       Note that the environment's localization	settings (particularly
       collation order)	may affect the result when comparing strings using the
       relational operators.

       For regular expression matches, the right operand is the	expression; it
       is expected to be a string in PCRE syntax.  For more information, see

       Parentheses can be used to override the normal order of operations when

       KL-EL defines a single ternary operator,	'?'.  Ternary expressions are
       of the form:

	   predicate ? expr1 : expr2

       where predicate is an expression	of Boolean type	and expr1 and expr2
       are two expressions of the same type.  If predicate evaluates to	true,
       expr1 is	evaluated, otherwise expr2 is evaluated.  Note that
       parenthesis are generally required around predicates unless they	are
       syntactically trivial.  The type	of a ternary expression	is the type of
       expr1 or	expr2.

       KL-EL is	lexically scoped in the	ALGOL tradition.  New environments are
       created using let expressions.  These expressions are of	the form:

	   let var = expr1 in expr2

       The value of this expression is the value of expr2 with every
       occurrence of var substituted by	the value of expr1.  As	let
       expressions are normal expressions, they	can be nested.	In particular,
       this is a valid (and common) idiom:

	   let var1 = expr1 in
	     let var2 =	expr2 in
	       let var3	= expr3	in
		 var1 +	var2 + var3

       Variables in nested scopes can shadow variables in outer	scopes,	though
       this functionality is best used sparingly.  Variables exported from the
       host application	are in the outermost scope.

       Aside from value	expressions, KL-EL supports guarded commands.  A
       guarded command consists	of a guard of boolean type, a call to the
       special function	eval, and an optional list of return codes.  The
       intent of guarded commands is to	provide	the host application with a
       command (where the meaning of "command" is defined by the host
       application), along with	a set of supporting arguments, that is valid
       only when the guard expression is valid.

       Guarded commands	have one of the	following forms:

	 if (guard) then eval(interpreter, program, arg0, ... argN)

	 if (guard) then eval(interpreter, program, arg0, ... argN) pass [code0, ... codeN]

	 if (guard) then eval(interpreter, program, arg0, ... argN) fail [code0, ... codeN]

       In these	forms guard must be a value expression of boolean type,
       interpreter and program must be constant	strings, and codes must	be
       literal integers.  The remaining	arguments may be of any	type.

       Guarded commands	are useful in situations where it is important to
       distinguish between the action and the guard.  Take for example a file-
       finding application.  In	this hypothetical application, a guarded
       command is used to specify a command to execute on every	file that
       matches its expression thereby allowing the application to customize
       its behavior based on observed file attributes.

       In a guarded command, the arguments to the eval function	and the	code
       values are passed as-is to the host application.	 It is up to the
       application to determine	their meaning.	For a discussion on how
       guarded commands	are represented	in host	applications, see klelapi(3).

       It is important to note that guarded commands cannot be nested inside
       other expressions or guarded commands.

       klel-expr(1), klelapi(3), klelstdlib(3),	kleltut(3), pcre(3)

1.1.0				  2021-02-28			   KLELLANG(1)


Want to link to this manual page? Use this URL:

home | help