Projects / Treep


Treep is a simple language for doing symbolical computations. It operates on numbers and strings that can be organized in more complex objects. These objects are lists of name-value pairs that are stored in memory as AVL trees. It has about sixty built-in functions to operate on such data and a way to define new functions. Treep syntax very much resembles Lisp. The power of treep is its simplicity and security. Treep is a good tool do process objects and relations between them. For example it is possible to define graphs as a sets of vertices and edges in text file, parse that file, do any computations you like, write modified data to text file. Treep works well on graphs, trees, linked lists, simple hashes. Treep is not good at processing texts, dealing with system input/output.

Operating Systems

Last announcement

Is treep fast or slow? 18 Oct 2011 15:22

What Treep does in 3 minutes: -- read/write 400 thousand (400.000) lines of text -- compute 15 million of user-defined function calls -- compute 110 million of built-in functions -- stack of values gets 600 thousand (600.000) values -- recursion (stack of calls) gets 200 thousand in depth

Recent releases

  •  02 Nov 2011 15:46

    Release Notes: This release has been optimized for speed, and is a few times faster than before. In the source code, "goto" is used to skip unnecessary checks, but this looks quite elegant.

    •  12 Oct 2011 16:27

      Release Notes: This release adds documentation for functions and adds some examples. The project has been moved moved to a new URL.

      •  11 Oct 2011 07:35

        Release Notes: Time handling was fixed and throughly tested.

        Release Notes: This release adds three functions for time handling: time (number of seconds since Epoch), repr (YYYY-MM-DD HH:MM:SS text representation), pars (to parse dates from text strings). In the library, it adds one function "like" which tests text for various formats.

        •  28 Sep 2011 08:39

          Release Notes: Time handling was updated. A function now computes Unix time, and you can convert it to number and name.

          Recent comments

          30 Sep 2011 14:33 leszek_dubiel

          Finally released treep that supports ISO 8601 date handling in format "YYYY-MM-DD HH:MM:SS" in range from "1901-12-13 20:45:52" until "2038-01-19 03:14:07". Regular expression that is hard to find on web is:

          ^(1901-12-13 (20:(45:5[2-9]|(4[6-9]|5[0-9]):[0-5][0-9])|2[1-3]:[0-5][0-9]:[0-5][0-9])|(1901-12-(1[4-9]|2[0-9]|3[01])|(19(0[2-9]|[1-9][0-9])|20([012][0-9]|3[0-7]))-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[1,3-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|(190[48]|(19[13579]|201)[26]|(19[2468]|20[02])[048]|203[26])-02-29|2038-01-(0[1-9]|1[0-8])) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|2038-01-19 (0[0-2]:[0-5][0-9]:[0-5][0-9]|03:((0[0-9]|1[0-3]):[0-5][0-9]|14:0[0-7])))$

          27 Jul 2011 07:18 leszek_dubiel

          I have made new version of treep:

          Treep is a simple language for doing symbolical computations. It operates
          on numbers and strings that can be organized in more complex objects. These
          objects are lists of name-value pairs that are stored in memory as AVL
          trees. It has about sixty built-in functions to operate on such data and
          a way to define new functions. Treep syntax very much resembles Lisp.
          Power of treep is it's simplicity.

          Treep reads expressions from standard input and evaluates them until end of
          file is reached. Evaluation can make some more data be read from standard
          input and some data be printed on stadard output or standard error.

          Every expression that is read from standard input must be a literal value,
          function call or function definition. Literal value is a number, a name or
          a text. This is all that can be put on program input.

          Numbers in Treep are defined by sign, set of integral numbers, dot and set
          of decimal numbers. All these parts are obligatory. Exception is zero, which
          is defined as "0.0". For example these are valid numbers: "+45.0", "-99.123",
          "+0.12". But these are not valid numbers: "-0.0" (sign not allowed for zero),
          "45.0" (sign is missing), "-34" (decimal part is missing), "-34.1000" (extra
          zeros at the end), "+04.56" (extra zeros at the beginning). Program checks
          if number is not bigger than allowed precission (long double in C).

          Names in Treep are set of letters, digits and underscores, but first
          character must be a letter, last character must not be underscore and no two
          underscores could be one after another. Names must match regular expression
          "^[A-Za-z](_?[A-Za-z0-9])*$". For example these are valid names: "alfa_1",
          "beta_1_XP", "my_name". These are not valid names: "my-home" (minus is
          neither letter, digit or underscore), "4you" (not a letter at the beginning),
          "Alfa_23_" (underscore at the end), "Alfa__34" (two undercores in a row).

          Text in Treep is a set of printable characters ([:print:] in C) enclosed in
          double quotes. There are allowed two escape sequences: "\"" (double quote)
          and "\\" (backslash).

          Function call is a set of expressions enclosed in parentheses. The first
          expression should evaluate to the name of function to be called. The rest of
          expressions are function call parameters. Parameters are evaluated in order
          from left to right. This means, that between parentheses there should be at
          least one expression. These are valid function calls:

          (add +4.5 -9.0)
          (info "Hello World!")
          ((evaluate_function_name) +5.6) .

          It is possible to define a new function. New function definitions are made
          of asterisk *, name of function, names of parameters enclosed in parentehses
          and body of the function. The body is an expression to evaluate when the
          function is called. Inside the body all parameters of the function are
          accessible as if they were defined as separate functions. Here is example
          of function that computes average of two numbers:

          * average (x y) (div (add (x) (y)) +2.0) .

          Name of function is "average" and it has two parameters named "x" and "y".
          This funciton is called like this:

          (average +4.0 +6.0) .

          While evaluation name "x" is assigned value "+4.0" and "y" is assigned value
          "+6.0". In the body of the function parameters can be accessed as if they
          were normal functions, so in example "(x)" will evaluate to "+4.0" and "(y)"
          to "+6.0". Treep then add these numbers and divides them by "+2.0". Finally
          whole function call has value "+5.0".

          Standard input to Treep besides expressions to evaluate and definitions of new
          functions could contain data that is read during expression evaluation. For
          example in such input:


          Treep will evaluate only two expressions, two calls of function read, because
          function "read" will swallow name "alfa" and then "beta" from standard input.

          COMPLEX DATA

          Treep has only one complex data type -- this is a list of name-value pairs
          that is stored in memory as AVL binary tree for fast access. Values can also
          be lists, so it is possible to read, build, analise very complex data types
          such as graphs, trees, linked lists.

          There is a full set of built-in functions that operate on trees. One can
          create new empty tree ("new" function), add and remove named elements
          from tree ("ins", "del"), modify value of named element in tree ("set"),
          retrieve value of named element ("get"). It is possible to access all elements
          of tree directly ("frst" -- first element of tree, "last", "left", "rght").


          Treep program works in a three-step loop. In the first step it skips spaces,
          tabs and new lines. In the second step it reads an expression. In the third
          step it evaluates that expression. It sounds very typical, but in the third
          step treep can evaluate functions "read" or "write" that cause some data be
          read from standard input or written to standard output. This is different
          from other programs, because expressions to evaluate and data for that
          expressions are all in the same data flow -- on standard input.

          Function "read" reads one piece of data from standard input. This can be a
          number, a name, a text, or a single character (one of space, tab, new line,
          left parenthesis or right parenthesis). Function "write" wirtes data to
          standard output. For example such treep input:

          (wrte (add (read) (read)))+4.0+2.0

          will cause treep to write "+6.0" on standard output.


          Treep has about sixty built-in functions. Some functions like "add" or
          "sub" are evaluated ordinarly -- treep first evaluates parameters of such a
          function, and then runs a code to compute the result. Other functions like
          "read" or "write" change state of input and output, functions "new", "set",
          "get", "ins", "del" change state of memory where data is stored. Treep has
          also three very special and important functions -- these are "if", "do" and
          "as" functions.

          Function "if" is used to evaluate expressions conditionally. First parameter
          is a condition to check. This is an expression that should have boolean
          value. If value is true, then following expression is evaluated and no more
          conditions are considered. When value of condition is false then following
          expression is skipped and next condition is considered. Finally if there
          is only one parameter left then it is used as "else expression" -- this is
          evaluated if all conditions are false.

          For example one can define function that computes nth Fibonacci number
          like this:

          * fib (n)
          (equ (n) 0.0) 0.0
          (equ (n) +1.0) +1.0
          (add (fib (sub (n) +1.0)) (fib (sub (n) +2.0)))
          ) .

          Function retunrs result that is evaluation of "if" function. Function "if"
          has five parameters. First parameter is a condition "(equ (n) 0.0)" that checks
          if number "n" is equal zero. If this is true, then following expression "0.0"
          is evaluated -- this is the result of whole function "fib" call in a case "n"
          is equal zero. If number "n" is not equal zero, then next condition "(equ (n)
          +1.0)" is checked. If this condition is true, then expression "+1.0" becomes
          a result. If both conditions are false, then the last expression is evaluated
          which adds two numbers "(fib (sub (n) +1.0))" and "(fib (sub (n) +2.0))".

          Function "as" is used to remember values by name, and thus to omit multiple
          evaluation of the same expression. This is extremely important for evaluating
          functions that cause side effects. For example function "read" gets data from
          input and one cannot read that data again -- after beeing read it has
          to be stored somewhere. This is can be done like this:

          * about_numbers ()
          x (read)
          y (read)
          "For " (x) " and " (y)
          " sum is " (add (x) (y))
          " and difference is " (sub (x) (y)) i

          (about_numbers)+6.0+7.5 .

          Treep reads and stores defintion of function "about_numbers". Then it reads
          first expression "(about_numbers)". The body of function "about_numbers" is
          computed. Function "as" first reads name "x", evaluates expression "(read)"
          and result is stored as name "x". The same happens with name "y". Then last
          parameter of function "as" is computed, where names "x" and "y" can be used as
          ordinary functions. In the example parameters of function "info" are computed,
          names "x" and "y" are used many times, but no more data is read from input.

          Function "do" is used to evaluate many expressions, especially when they
          cause side effects, by discarding some of results. Parameters of function
          "do" are evaluated from left to right and the value of last parameter becomes
          the value of the whole expression. Here is an example of function that divides
          numbers and when division by zero would occur it prints warning to standard
          error and returns zero:

          * safe_divide (x y)
          (equ 0.0 (y)) (do (info "division by zero occured") 0.0)
          (div (x) (y))

          (safe_divide +2.0 +5.0)
          (safe_divide +9.99 0.0)
          (safe_divide +4.0 -3.0) .

          LEARN MORE

          In directory "read.d" there is a set of files that should be passed on
          standard input to "treep" program. This files demonstrate Treep usage step
          by step and are intended to show all treep functionality in detail.

          09 Nov 2010 07:52 leszek_dubiel

          # n-th fibbonaci number
          * fib (n)
          (if (gre (n) +2.0)
          (add (fib (dec (n))) (fib (dec (dec (n)))))

          (info (fib +4.0))
          (info (fib +5.0))
          (info (fib +6.0))
          (info (fib +7.0))

          09 Nov 2010 07:33 leszek_dubiel

          Here is example how looks code for treep:

          # List is an ordered set of elements. Each element has a name and a parame-
          # ters. Here is example of list:
          # (
          # Lustro_Omni (Qty -45.0 Who "Kowlaski Sp. z o.o")
          # Lustro_Atos (Qty -4.0)
          # Lustro_Pluton (Qty -9.0 When '2009-12-31')
          # Lustro_Helios (Qty -1.0)
          # ) .
          # Every list element has fields "name", "parm" and "next".

          # read or write a list
          * list_read ()
          (if (is lpar (read))
          (do (info "Can not compute \"list_read\" call. Parenthesis was expected.") (exit (no)))
          (list_read_elem (do (skip) (read)))
          * list_read_elem (n)
          (if (is rpar (n))
          (if (is name (n))
          (do (info "Can not compute \"list_read\" call. Name of list element was expected.") (exit (no)))
          l (new)
          (ins (l) name (n))
          (ins (l) parm (do (skip) (parm_read)))
          (ins (l) next (list_read_elem (do (skip) (read))))
          * list_wrte (l)
          (wrte (lpar))
          (wrte (line))
          (list_wrte_elem (l))
          * list_wrte_elem (l)
          (if (is void (l))
          (wrte (rpar))
          (wrte (tabu))
          (wrte (get (l) name))
          (wrte (spac))
          (parm_wrte (get (l) parm))
          (wrte (line))
          (list_wrte_elem (get (l) next))

          # apply notes to list
          * list_note (l n)
          (if (is void (l))
          (note_aply (n) (get (l) name) (get (l) parm))
          (list_note (get (l) next) (n))


          Project Spotlight


          A Fluent OpenStack client API for Java.


          Project Spotlight

          TurnKey TWiki Appliance

          A TWiki appliance that is easy to use and lightweight.