diff --git a/ast.go b/ast.go
index 6d1bb35..8aadfd4 100644
--- a/ast.go
+++ b/ast.go
@@ -10,11 +10,15 @@ import (
 	"strings"
 )
 
+type Expr interface {
+	Eval(ctx exprContext, preset bool) (result any, err error)
+}
+
 //-------- ast
 
 type ast struct {
 	forest []*term
-	root *term
+	root   *term
 }
 
 func NewAst() *ast {
@@ -54,7 +58,7 @@ func (self *ast) addToken(tk *Token) (err error) {
 	if t := newTerm(tk, nil); t != nil {
 		err = self.addTerm(t)
 	} else {
-		err = fmt.Errorf("No term constructor for token %q", tk.String())
+		err = tk.Errorf("No term constructor for token %q", tk.String())
 	}
 	return
 }
@@ -83,23 +87,25 @@ func (self *ast) insert(tree, node *term) (root *term, err error) {
 		root = node
 		tree.setParent(node)
 	} else {
-		err = fmt.Errorf("two adjacent operators: %q and %q", tree, node)
+		err = node.Errorf("two adjacent operators: %q and %q", tree, node)
 	}
 	return
 }
 
 func (self *ast) Finish() {
-        if self.root == nil && self.forest != nil && len(self.forest) >= 1 {
-                self.root = self.forest[len(self.forest)-1]
-                self.forest = self.forest[0:len(self.forest) - 1]
-        }
+	if self.root == nil && self.forest != nil && len(self.forest) >= 1 {
+		self.root = self.forest[len(self.forest)-1]
+		self.forest = self.forest[0 : len(self.forest)-1]
+	}
 }
 
-func (self *ast) Eval(ctx exprContext) (result any, err error) {
+func (self *ast) Eval(ctx exprContext, preset bool) (result any, err error) {
 	self.Finish()
 
 	if self.root != nil {
-		initDefaultVars(ctx)
+		if preset {
+			initDefaultVars(ctx)
+		}
 		if self.forest != nil {
 			for i, root := range self.forest {
 				if result, err = root.compute(ctx); err == nil {
@@ -121,7 +127,7 @@ func (self *ast) Eval(ctx exprContext) (result any, err error) {
 
 // Preset variables
 const (
-	preset_last_result = "_last"
+	preset_last_result   = "_last"
 	preset_bool_shortcut = "_bool_shortcut"
 )
 
diff --git a/ast_test.go b/ast_test.go
index 2e68234..67d0c2e 100644
--- a/ast_test.go
+++ b/ast_test.go
@@ -17,9 +17,9 @@ func TestAstString(t *testing.T) {
 }
 
 func TestAddTokensGood(t *testing.T) {
-	tk1 := NewValueToken(SymInteger, "100", 100)
-	tk2 := NewToken(SymPlus, "+")
-	tk3 := NewValueToken(SymInteger, "50", 500)
+	tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
+	tk2 := NewToken(0, 0, SymPlus, "+")
+	tk3 := NewValueToken(0, 0, SymInteger, "50", 500)
 
 	tree := NewAst()
 	if gotErr := tree.addTokens(tk1, tk2, tk3); gotErr != nil {
@@ -28,12 +28,12 @@ func TestAddTokensGood(t *testing.T) {
 }
 
 func TestAddTokensBad(t *testing.T) {
-	tk0 := NewValueToken(SymInteger, "200", 200)
-	tk1 := NewValueToken(SymInteger, "100", 100)
-	tk2 := NewToken(SymPlus, "+")
-	tk3 := NewValueToken(SymInteger, "50", 500)
+	tk0 := NewValueToken(0, 0, SymInteger, "200", 200)
+	tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
+	tk2 := NewToken(0, 0, SymPlus, "+")
+	tk3 := NewValueToken(0, 0, SymInteger, "50", 500)
 
-	wantErr := errors.New(`two adjacent operators: "200" and "100"`)
+	wantErr := errors.New(`[0:0] two adjacent operators: "200" and "100"`)
 
 	tree := NewAst()
 	if gotErr := tree.addTokens(tk0, tk1, tk2, tk3); gotErr != nil && gotErr.Error() != wantErr.Error() {
@@ -42,7 +42,7 @@ func TestAddTokensBad(t *testing.T) {
 }
 
 func TestAddUnknownTokens(t *testing.T) {
-	tk0 := NewToken(SymPercent, "%")
+	tk0 := NewToken(0, 0, SymPercent, "%")
 
 	wantErr := errors.New(`No term constructor for token "%"`)
 
diff --git a/context.go b/context.go
index 37fd1b9..7ae7fd4 100644
--- a/context.go
+++ b/context.go
@@ -4,18 +4,35 @@
 // context.go
 package expr
 
+// ---- Function template
 type FuncTemplate func(ctx exprContext, name string, args []any) (result any, err error)
 
+// ---- Functor interface
+type Functor interface {
+	Invoke(ctx exprContext, name string, args []any) (result any, err error)
+}
+
+type simpleFunctor struct {
+	f FuncTemplate
+}
+
+func (functor *simpleFunctor) Invoke(ctx exprContext, name string, args []any) (result any, err error) {
+	return functor.f(ctx, name, args)
+}
+
+// ---- Function Info
 type exprFunc interface {
 	Name() string
 	MinArgs() int
 	MaxArgs() int
 }
 
+// ----Expression Context
 type exprContext interface {
+	Clone() exprContext
 	GetValue(varName string) (value any, exists bool)
 	SetValue(varName string, value any)
 	GetFuncInfo(name string) exprFunc
 	Call(name string, args []any) (result any, err error)
-	RegisterFunc(name string, f FuncTemplate, minArgs, maxArgs int)
+	RegisterFunc(name string, f Functor, minArgs, maxArgs int)
 }
diff --git a/funcs-math.go b/funcs-math.go
index 567adbd..121dd51 100644
--- a/funcs-math.go
+++ b/funcs-math.go
@@ -134,6 +134,6 @@ func mulFunc(ctx exprContext, name string, args []any) (result any, err error) {
 }
 
 func importMathFuncs(ctx exprContext) {
-	ctx.RegisterFunc("add", addFunc, 0, -1)
-	ctx.RegisterFunc("mul", mulFunc, 0, -1)
+	ctx.RegisterFunc("add", &simpleFunctor{f: addFunc}, 0, -1)
+	ctx.RegisterFunc("mul", &simpleFunctor{f: mulFunc}, 0, -1)
 }
diff --git a/helpers.go b/helpers.go
index 3fbdf68..1765974 100644
--- a/helpers.go
+++ b/helpers.go
@@ -14,7 +14,7 @@ func EvalString(ctx exprContext, source string) (result any, err error) {
 	parser := NewParser(ctx)
 
 	if tree, err = parser.parse(scanner); err == nil {
-		result, err = tree.Eval(ctx)
+		result, err = tree.Eval(ctx, true)
 	}
 	return
 }
@@ -33,7 +33,8 @@ func EvalStringV(source string, args []EvalArg) (result any, err error) {
 	for _, arg := range args {
 		if isFunc(arg.value) {
 			if f, ok := arg.value.(FuncTemplate); ok {
-				ctx.RegisterFunc(arg.name, f, 0, -1)
+				functor := &simpleFunctor{f: f}
+				ctx.RegisterFunc(arg.name, functor, 0, -1)
 			} else {
 				err = fmt.Errorf("invalid function specification: %q", arg.name)
 			}
diff --git a/operand-expr.go b/operand-expr.go
new file mode 100644
index 0000000..ae433a4
--- /dev/null
+++ b/operand-expr.go
@@ -0,0 +1,36 @@
+// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
+// All rights reserved.
+
+// operand-expr.go
+package expr
+
+import "errors"
+
+// -------- expr term
+func newExprTerm(tk *Token) *term {
+	return &term{
+		tk:       *tk,
+		class:    classVar,
+		kind:     kindUnknown,
+		parent:   nil,
+		children: nil,
+		position: posLeaf,
+		priority: priValue,
+		evalFunc: evalExpr,
+	}
+}
+
+// -------- eval expr
+func evalExpr(ctx exprContext, self *term) (v any, err error) {
+	if expr, ok := self.value().(Expr); ok {
+		v, err = expr.Eval(ctx, false)
+	} else {
+		err = errors.New("invalid body of function definition")
+	}
+	return
+}
+
+// init
+// func init() {
+// 	registerTermConstructor(SymExpression, newExprTerm)
+// }
diff --git a/operand-func.go b/operand-func.go
index 6975c63..3e18afd 100644
--- a/operand-func.go
+++ b/operand-func.go
@@ -4,8 +4,13 @@
 // operand-func.go
 package expr
 
-// -------- function term
-func newFuncTerm(tk *Token, args []*term) *term {
+import (
+	"errors"
+	"fmt"
+)
+
+// -------- function call term
+func newFuncCallTerm(tk *Token, args []*term) *term {
 	return &term{
 		tk:       *tk,
 		class:    classVar,
@@ -14,12 +19,12 @@ func newFuncTerm(tk *Token, args []*term) *term {
 		children: args,
 		position: posLeaf,
 		priority: priValue,
-		evalFunc: evalFunc,
+		evalFunc: evalFuncCall,
 	}
 }
 
-// -------- eval func
-func evalFunc(ctx exprContext, self *term) (v any, err error) {
+// -------- eval func call
+func evalFuncCall(ctx exprContext, self *term) (v any, err error) {
 	name, _ := self.tk.Value.(string)
 	params := make([]any, len(self.children))
 	for i, tree := range self.children {
@@ -34,3 +39,59 @@ func evalFunc(ctx exprContext, self *term) (v any, err error) {
 	}
 	return
 }
+
+// -------- function definition term
+func newFuncDefTerm(tk *Token, args []*term) *term {
+	return &term{
+		tk:       *tk,
+		class:    classVar,
+		kind:     kindUnknown,
+		parent:   nil,
+		children: args, // arg[0]=formal-param-list, arg[1]=*ast
+		position: posLeaf,
+		priority: priValue,
+		evalFunc: evalFuncDef,
+	}
+}
+
+// -------- eval func def
+// TODO
+type funcDefFunctor struct {
+	params []string
+	expr   Expr
+}
+
+func (functor *funcDefFunctor) Invoke(parentCtx exprContext, name string, args []any) (result any, err error) {
+	ctx := parentCtx.Clone()
+	for i, p := range functor.params {
+		if i < len(args) {
+			ctx.SetValue(p, args[i])
+		} else {
+			ctx.SetValue(p, nil)
+		}
+	}
+	result, err = functor.expr.Eval(ctx, false)
+	return
+}
+
+func evalFuncDef(ctx exprContext, self *term) (v any, err error) {
+	bodySpec := self.value()
+	if expr, ok := bodySpec.(*ast); ok {
+		paramList := make([]string, 0, len(self.children))
+		for i, param := range self.children {
+			if paramName, ok := param.value().(string); ok {
+				paramList = append(paramList, paramName)
+			} else {
+				err = fmt.Errorf("invalid function definition: formal param nr %d must be an identifiers", i+1)
+				break
+			}
+		}
+		v = &funcDefFunctor{
+			params: paramList,
+			expr:   expr,
+		}
+	} else {
+		err = errors.New("invalid function definition: the body specification must be an expression")
+	}
+	return
+}
diff --git a/operand-list.go b/operand-list.go
index 9a52522..39bf8ef 100644
--- a/operand-list.go
+++ b/operand-list.go
@@ -7,7 +7,7 @@ package expr
 // -------- list term
 func newListTerm(args []*term) *term {
 	return &term{
-		tk:       *NewToken(SymList, "[]"),
+		tk:       *NewToken(0, 0, SymList, "[]"),
 		class:    classVar,
 		kind:     kindUnknown,
 		parent:   nil,
diff --git a/operator-assign.go b/operator-assign.go
index 76062ba..d6e3367 100644
--- a/operator-assign.go
+++ b/operator-assign.go
@@ -4,8 +4,6 @@
 // operator-assign.go
 package expr
 
-import "fmt"
-
 //-------- assign term
 
 func newAssignTerm(tk *Token) (inst *term) {
@@ -27,12 +25,16 @@ func evalAssign(ctx exprContext, self *term) (v any, err error) {
 
 	leftTerm := self.children[0]
 	if leftTerm.tk.Sym != SymIdentifier {
-		err = fmt.Errorf("left operand of %q must be a variable", self.tk.source)
+		err = leftTerm.tk.Errorf("left operand of %q must be a variable", self.tk.source)
 		return
 	}
 
 	if v, err = self.children[1].compute(ctx); err == nil {
-		ctx.SetValue(leftTerm.tk.source, v)
+		if functor, ok := v.(Functor); ok {
+			ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
+		} else {
+			ctx.SetValue(leftTerm.tk.source, v)
+		}
 	}
 	return
 }
diff --git a/parser.go b/parser.go
index ec7b127..a1a2ab7 100644
--- a/parser.go
+++ b/parser.go
@@ -5,6 +5,7 @@
 package expr
 
 import (
+	"errors"
 	"fmt"
 )
 
@@ -21,22 +22,23 @@ func NewParser(ctx exprContext) (p *parser) {
 	return p
 }
 
-func (self *parser) parseFunction(scanner *scanner, tk *Token) (tree *term, err error) {
-	name, _ := tk.Value.(string)
-	funcObj := self.ctx.GetFuncInfo(name)
-	if funcObj == nil {
-		err = fmt.Errorf("unknown function %s()", name)
-		return
-	}
-	maxArgs := funcObj.MaxArgs()
-	if maxArgs < 0 {
-		maxArgs = funcObj.MinArgs() + 10
-	}
-	args := make([]*term, 0, maxArgs)
+func (self *parser) parseFuncCall(scanner *scanner, tk *Token) (tree *term, err error) {
+	// name, _ := tk.Value.(string)
+	// funcObj := self.ctx.GetFuncInfo(name)
+	// if funcObj == nil {
+	// 	err = fmt.Errorf("unknown function %s()", name)
+	// 	return
+	// }
+	// maxArgs := funcObj.MaxArgs()
+	// if maxArgs < 0 {
+	// 	maxArgs = funcObj.MinArgs() + 10
+	// }
+	// args := make([]*term, 0, maxArgs)
+	args := make([]*term, 0, 10)
 	lastSym := SymUnknown
 	for lastSym != SymClosedRound && lastSym != SymEos {
 		var subTree *ast
-		if subTree, err = self.parse(scanner, SymComma, SymClosedRound); err == nil {
+		if subTree, err = self.parseItem(scanner, SymComma, SymClosedRound); err == nil {
 			if subTree.root != nil {
 				args = append(args, subTree.root)
 			}
@@ -47,7 +49,47 @@ func (self *parser) parseFunction(scanner *scanner, tk *Token) (tree *term, err
 	}
 	if err == nil {
 		// TODO Check arguments
-		tree = newFuncTerm(tk, args)
+		if lastSym != SymClosedRound {
+			err = errors.New("unterminate arguments list")
+		} else {
+			tree = newFuncCallTerm(tk, args)
+		}
+	}
+	return
+}
+
+func (self *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
+	// Example: "add = func(x,y) {x+y}
+	var body *ast
+	args := make([]*term, 0)
+	tk := scanner.Next()
+	for tk.Sym != SymClosedRound && tk.Sym != SymEos {
+		if tk.Sym == SymIdentifier {
+			t := newTerm(tk, nil)
+			args = append(args, t)
+		} else {
+			err = tk.Errorf("invalid param %q, variable identifier expected", tk.source)
+			break
+		}
+		tk = scanner.Next()
+	}
+	if err == nil && tk.Sym != SymClosedRound {
+		err = tk.Errorf("unterminate function params list")
+	}
+	if err == nil {
+		tk = scanner.Next()
+		if tk.Sym == SymOpenBrace {
+			body, err = self.parseGeneral(scanner, true, SymClosedBrace)
+		}
+	}
+	if err == nil {
+		// TODO Check arguments
+		if scanner.Previous().Sym != SymClosedBrace {
+			err = scanner.Previous().Errorf("unterminate function body")
+		} else {
+			tk = scanner.makeValueToken(SymExpression, "", body)
+			tree = newFuncDefTerm(tk, args)
+		}
 	}
 	return
 }
@@ -57,7 +99,7 @@ func (self *parser) parseList(scanner *scanner) (tree *term, err error) {
 	lastSym := SymUnknown
 	for lastSym != SymClosedSquare && lastSym != SymEos {
 		var subTree *ast
-		if subTree, err = self.parse(scanner, SymComma, SymClosedSquare); err == nil {
+		if subTree, err = self.parseItem(scanner, SymComma, SymClosedSquare); err == nil {
 			if subTree.root != nil {
 				args = append(args, subTree.root)
 			}
@@ -68,12 +110,24 @@ func (self *parser) parseList(scanner *scanner) (tree *term, err error) {
 	}
 	if err == nil {
 		// TODO Check arguments
-		tree = newListTerm(args)
+		if lastSym != SymClosedSquare {
+			err = scanner.Previous().Errorf("unterminate items list")
+		} else {
+			tree = newListTerm(args)
+		}
 	}
 	return
 }
 
 func (self *parser) parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) {
+	return self.parseGeneral(scanner, true, termSymbols...)
+}
+
+func (self *parser) parseItem(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) {
+	return self.parseGeneral(scanner, false, termSymbols...)
+}
+
+func (self *parser) parseGeneral(scanner *scanner, allowForset bool, termSymbols ...Symbol) (tree *ast, err error) {
 	tree = NewAst()
 	firstToken := true
 	lastSym := SymUnknown
@@ -83,19 +137,25 @@ func (self *parser) parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, e
 		}
 
 		if tk.Sym == SymSemiColon {
-			tree.ToForest()
-			continue
+			if allowForset {
+				tree.ToForest()
+				continue
+			} else {
+				err = tk.Errorf(`unexpected token %q, expected ",", "]", or ")"`, tk.source)
+				break
+			}
 		}
 
 		//fmt.Println("Token:", tk)
-		if firstToken && (tk.Sym == SymMinus || tk.Sym == SymPlus) {
+		if firstToken {
 			if tk.Sym == SymMinus {
 				tk.Sym = SymChangeSign
-			} else {
+			} else if tk.Sym == SymPlus {
 				tk.Sym = SymUnchangeSign
 			}
+			firstToken = false
 		}
-		firstToken = false
+
 		switch tk.Sym {
 		case SymOpenRound:
 			var subTree *ast
@@ -103,10 +163,10 @@ func (self *parser) parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, e
 				subTree.root.priority = priValue
 				tree.addTerm(subTree.root)
 			}
-		case SymFunction:
-			var funcTerm *term
-			if funcTerm, err = self.parseFunction(scanner, tk); err == nil {
-				err = tree.addTerm(funcTerm)
+		case SymFuncCall:
+			var funcCallTerm *term
+			if funcCallTerm, err = self.parseFuncCall(scanner, tk); err == nil {
+				err = tree.addTerm(funcCallTerm)
 			}
 		case SymOpenSquare:
 			var listTerm *term
@@ -114,10 +174,13 @@ func (self *parser) parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, e
 				err = tree.addTerm(listTerm)
 			}
 		case SymEqual:
-			if lastSym == SymIdentifier {
+			if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil {
 				err = tree.addToken(tk)
-			} else {
-				err = fmt.Errorf(`assign operator (%q) must be preceded by a variable`, tk.source)
+			}
+		case SymFuncDef:
+			var funcDefTerm *term
+			if funcDefTerm, err = self.parseFuncDef(scanner); err == nil {
+				err = tree.addTerm(funcDefTerm)
 			}
 		default:
 			err = tree.addToken(tk)
@@ -126,3 +189,10 @@ func (self *parser) parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, e
 	}
 	return
 }
+
+func checkPrevSymbol(lastSym, wantedSym Symbol, tk *Token) (err error) {
+	if lastSym != wantedSym {
+		err = fmt.Errorf(`assign operator (%q) must be preceded by a variable`, tk.source)
+	}
+	return
+}
diff --git a/parser_test.go b/parser_test.go
index 5a9a982..31f8649 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -18,12 +18,6 @@ func TestParser(t *testing.T) {
 		wantErr    error
 	}
 
-	// inputs1 := []inputType{
-	// 	{`a=5; a`, int64(5), nil},
-	// 	{`a=5; b=2; add(a, b*3)`, int64(11), nil},
-	// 	{`"a" < "b" AND ~ 2 == 1`, true, nil},
-	// }
-
 	inputs := []inputType{
 		/*   1 */ {`1+/*5*/2`, int64(3), nil},
 		/*   2 */ {`3 == 4`, false, nil},
@@ -66,10 +60,10 @@ func TestParser(t *testing.T) {
 		/*  39 */ {`(((1)))`, int64(1), nil},
 		/*  40 */ {`"uno_" + var2`, `uno_abc`, nil},
 		/*  41 */ {`0 || 0.0 && "hello"`, false, nil},
-		/*  42 */ {`"s" + true`, nil, errors.New(`left operand 's' [string] and right operand 'true' [bool] are not compatible with operator "+"`)},
-		/*  43 */ {`+false`, nil, errors.New(`prefix/postfix operator "+" do not support operand 'false' [bool]`)},
+		/*  42 */ {`"s" + true`, nil, errors.New(`[1:6] left operand 's' [string] and right operand 'true' [bool] are not compatible with operator "+"`)},
+		/*  43 */ {`+false`, nil, errors.New(`[1:2] prefix/postfix operator "+" do not support operand 'false' [bool]`)},
 		/*  44 */ {`false // very simple expression`, false, nil},
-		/*  45 */ {`1 + // Missing right operator`, nil, errors.New(`infix operator "+" requires two operands, got 1`)},
+		/*  45 */ {`1 + // Missing right operator`, nil, errors.New(`[1:4] infix operator "+" requires two operands, got 1`)},
 		/*  46 */ {"", nil, errors.New(`empty expression`)},
 		/*  47 */ {"4!", int64(24), nil},
 		/*  48 */ {"(-4)!", nil, errors.New(`factorial of a negative integer (-4) is not allowed`)},
@@ -84,18 +78,18 @@ func TestParser(t *testing.T) {
 		/*  57 */ {`"1.5" > "7"`, false, nil},
 		/*  58 */ {`"1.5" == "7"`, false, nil},
 		/*  59 */ {`"1.5" != "7"`, true, nil},
-		/*  60 */ {"1.5 < ", nil, errors.New(`infix operator "<" requires two operands, got 1`)},
-		/*  61 */ {"1.5 > ", nil, errors.New(`infix operator ">" requires two operands, got 1`)},
-		/*  62 */ {"1.5 <= ", nil, errors.New(`infix operator "<=" requires two operands, got 1`)},
-		/*  63 */ {"1.5 >= ", nil, errors.New(`infix operator ">=" requires two operands, got 1`)},
-		/*  64 */ {"1.5 != ", nil, errors.New(`infix operator "!=" requires two operands, got 1`)},
-		/*  65 */ {"1.5 == ", nil, errors.New(`infix operator "==" requires two operands, got 1`)},
-		/*  66 */ {`"1.5" < `, nil, errors.New(`infix operator "<" requires two operands, got 1`)},
-		/*  67 */ {`"1.5" > `, nil, errors.New(`infix operator ">" requires two operands, got 1`)},
-		/*  68 */ {`"1.5" == `, nil, errors.New(`infix operator "==" requires two operands, got 1`)},
-		/*  69 */ {`"1.5" != `, nil, errors.New(`infix operator "!=" requires two operands, got 1`)},
+		/*  60 */ {"1.5 < ", nil, errors.New(`[1:6] infix operator "<" requires two operands, got 1`)},
+		/*  61 */ {"1.5 > ", nil, errors.New(`[1:6] infix operator ">" requires two operands, got 1`)},
+		/*  62 */ {"1.5 <= ", nil, errors.New(`[1:6] infix operator "<=" requires two operands, got 1`)},
+		/*  63 */ {"1.5 >= ", nil, errors.New(`[1:6] infix operator ">=" requires two operands, got 1`)},
+		/*  64 */ {"1.5 != ", nil, errors.New(`[1:6] infix operator "!=" requires two operands, got 1`)},
+		/*  65 */ {"1.5 == ", nil, errors.New(`[1:6] infix operator "==" requires two operands, got 1`)},
+		/*  66 */ {`"1.5" < `, nil, errors.New(`[1:8] infix operator "<" requires two operands, got 1`)},
+		/*  67 */ {`"1.5" > `, nil, errors.New(`[1:8] infix operator ">" requires two operands, got 1`)},
+		/*  68 */ {`"1.5" == `, nil, errors.New(`[1:8] infix operator "==" requires two operands, got 1`)},
+		/*  69 */ {`"1.5" != `, nil, errors.New(`[1:8] infix operator "!=" requires two operands, got 1`)},
 		/*  70 */ {"+1.5", float64(1.5), nil},
-		/*  71 */ {"+", nil, errors.New(`prefix operator "+" requires one operand`)},
+		/*  71 */ {"+", nil, errors.New(`[1:2] prefix operator "+" requires one operand`)},
 		/*  72 */ {"4 / 0", nil, errors.New(`division by zero`)},
 		/*  73 */ {"4.0 / 0", nil, errors.New(`division by zero`)},
 		/*  74 */ {"4.0 / \n2", float64(2.0), nil},
@@ -109,7 +103,7 @@ func TestParser(t *testing.T) {
 		/*  82 */ {`5 % 2`, int64(1), nil},
 		/*  83 */ {`5 % (-2)`, int64(1), nil},
 		/*  84 */ {`-5 % 2`, int64(-1), nil},
-		/*  85 */ {`5 % 2.0`, nil, errors.New(`left operand '5' [int64] and right operand '2' [float64] are not compatible with operator "%"`)},
+		/*  85 */ {`5 % 2.0`, nil, errors.New(`[1:4] left operand '5' [int64] and right operand '2' [float64] are not compatible with operator "%"`)},
 		/*  86 */ {`"a" < "b" AND NOT (2 < 1)`, true, nil},
 		/*  87 */ {`"a" < "b" AND NOT (2 == 1)`, true, nil},
 		/*  88 */ {`"a" < "b" AND ~ 2 == 1`, true, nil},
@@ -129,12 +123,24 @@ func TestParser(t *testing.T) {
 		/* 102 */ {`a=5; a`, int64(5), nil},
 		/* 103 */ {`a=5; b=2; add(a, b*3)`, int64(11), nil},
 		/* 104 */ {`2=5`, nil, errors.New(`assign operator ("=") must be preceded by a variable`)},
-		/* 105 */ {`2+a=5`, nil, errors.New(`left operand of "=" must be a variable`)},
+		/* 105 */ {`2+a=5`, nil, errors.New(`[1:3] left operand of "=" must be a variable`)},
 		/* 106 */ {`2+(a=5)`, int64(7), nil},
+		/* 107 */ {`two=func(){2}; two()`, int64(2), nil},
+		/* 108 */ {`double=func(x) {2*x}; (double(3))`, int64(6), nil},
+		/* 109 */ {`double=func(x){2*x}; double(3)`, int64(6), nil},
+		/* 110 */ {`double=func(x){2*x}; a=5; double(3+a) + 1`, int64(17), nil},
+		/* 111 */ {`double=func(x){2*x}; a=5; two=func() {2}; (double(3+a) + 1) * two()`, int64(34), nil},
 	}
 	succeeded := 0
 	failed := 0
 
+	// inputs1 := []inputType{
+	// {`add(1,2,3)`, int64(6), nil},
+	// 	{`a=5; a`, int64(5), nil},
+	// 	{`a=5; b=2; add(a, b*3)`, int64(11), nil},
+	// 	{`"a" < "b" AND ~ 2 == 1`, true, nil},
+	// }
+
 	for i, input := range inputs {
 		var expr *ast
 		var gotResult any
@@ -153,7 +159,7 @@ func TestParser(t *testing.T) {
 
 		good := true
 		if expr, gotErr = parser.parse(scanner); gotErr == nil {
-			gotResult, gotErr = expr.Eval(ctx)
+			gotResult, gotErr = expr.Eval(ctx, true)
 		}
 
 		if gotResult != input.wantResult {
@@ -177,7 +183,7 @@ func TestParser(t *testing.T) {
 	t.Log(fmt.Sprintf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed))
 }
 
-func NoTestListParser(t *testing.T) {
+func TestListParser(t *testing.T) {
 	type inputType struct {
 		source     string
 		wantResult any
@@ -227,7 +233,7 @@ func NoTestListParser(t *testing.T) {
 
 		good := true
 		if expr, gotErr = parser.parse(scanner); gotErr == nil {
-			gotResult, gotErr = expr.Eval(ctx)
+			gotResult, gotErr = expr.Eval(ctx, true)
 		}
 
 		if (gotResult == nil && input.wantResult != nil) || (gotResult != nil && input.wantResult == nil) {
diff --git a/scanner.go b/scanner.go
index 4dd3b95..b45a542 100644
--- a/scanner.go
+++ b/scanner.go
@@ -229,8 +229,12 @@ func (self *scanner) fetchNextToken() (tk *Token) {
 			}
 			escape = false
 		default:
-			if ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
-				tk = self.fetchIdentifier(ch)
+			if /*ch == '_' ||*/ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
+				if tk = self.fetchIdentifier(ch); tk.Sym == SymKwFunc {
+					if next, _ := self.peek(); next == '(' {
+						tk = self.moveOn(SymFuncDef, ch, next)
+					}
+				}
 			} else if ch >= '0' && ch <= '9' {
 				tk = self.parseNumber(ch)
 			}
@@ -337,7 +341,7 @@ func (self *scanner) fetchIdentifier(firstCh byte) (tk *Token) {
 			tk = self.makeValueToken(SymBool, txt, false)
 		} else if ch, _ := self.peek(); ch == '(' {
 			self.readChar()
-			tk = self.makeValueToken(SymFunction, txt+"(", txt)
+			tk = self.makeValueToken(SymFuncCall, txt+"(", txt)
 		} else {
 			tk = self.makeValueToken(SymIdentifier, txt, txt)
 		}
@@ -533,7 +537,7 @@ func (self *scanner) translate(sym Symbol) Symbol {
 }
 
 func (self *scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
-	tk = NewToken(self.translate(sym), string(chars))
+	tk = NewToken(self.row, self.column, self.translate(sym), string(chars))
 	for i := 1; i < len(chars); i++ {
 		self.readChar()
 	}
@@ -541,17 +545,17 @@ func (self *scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
 }
 
 func (self *scanner) makeToken(sym Symbol, chars ...byte) (tk *Token) {
-	tk = NewToken(self.translate(sym), string(chars))
+	tk = NewToken(self.row, self.column, self.translate(sym), string(chars))
 	return
 }
 
 func (self *scanner) makeKeywordToken(sym Symbol, upperCaseKeyword string) (tk *Token) {
-	tk = NewToken(self.translate(sym), upperCaseKeyword)
+	tk = NewToken(self.row, self.column, self.translate(sym), upperCaseKeyword)
 	return
 }
 
 func (self *scanner) makeValueToken(sym Symbol, source string, value any) (tk *Token) {
-	tk = NewValueToken(self.translate(sym), source, value)
+	tk = NewValueToken(self.row, self.column, self.translate(sym), source, value)
 	return
 }
 
diff --git a/simple-func-store.go b/simple-func-store.go
index cfd1d6e..a55c509 100644
--- a/simple-func-store.go
+++ b/simple-func-store.go
@@ -5,7 +5,7 @@ import "fmt"
 
 type SimpleFuncStore struct {
 	varStore  map[string]any
-	funcStore map[string]FuncTemplate
+	funcStore map[string]Functor
 }
 
 type funcInfo struct {
@@ -29,7 +29,14 @@ func (info *funcInfo) MaxArgs() int {
 func NewSimpleFuncStore() *SimpleFuncStore {
 	return &SimpleFuncStore{
 		varStore:  make(map[string]any),
-		funcStore: make(map[string]FuncTemplate),
+		funcStore: make(map[string]Functor),
+	}
+}
+
+func (ctx *SimpleFuncStore) Clone() exprContext {
+	return &SimpleFuncStore{
+		varStore:  CloneMap(ctx.varStore),
+		funcStore: CloneMap(ctx.funcStore),
 	}
 }
 
@@ -50,13 +57,13 @@ func (ctx *SimpleFuncStore) GetFuncInfo(name string) (f exprFunc) {
 	return
 }
 
-func (ctx *SimpleFuncStore) RegisterFunc(name string, f FuncTemplate, minArgs, maxArgs int) {
-	ctx.funcStore[name] = f
+func (ctx *SimpleFuncStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
+	ctx.funcStore[name] = functor
 }
 
 func (ctx *SimpleFuncStore) Call(name string, args []any) (result any, err error) {
-	if f, exists := ctx.funcStore[name]; exists {
-		result, err = f(ctx, name, args)
+	if functor, exists := ctx.funcStore[name]; exists {
+		result, err = functor.Invoke(ctx, name, args)
 	} else {
 		err = fmt.Errorf("unknown function %s()", name)
 	}
diff --git a/simple-var-store.go b/simple-var-store.go
index ae89a36..613ec9c 100644
--- a/simple-var-store.go
+++ b/simple-var-store.go
@@ -11,6 +11,13 @@ func NewSimpleVarStore() *SimpleVarStore {
 	}
 }
 
+func (ctx *SimpleVarStore) Clone() (clone exprContext) {
+	clone = &SimpleVarStore{
+		store: CloneMap(ctx.store),
+	}
+	return clone
+}
+
 func (ctx *SimpleVarStore) GetValue(varName string) (v any, exists bool) {
 	v, exists = ctx.store[varName]
 	return
@@ -28,5 +35,5 @@ func (ctx *SimpleVarStore) Call(name string, args []any) (result any, err error)
 	return
 }
 
-func (ctx *SimpleVarStore) RegisterFunc(name string, f FuncTemplate, minArgs, maxArgs int) {
+func (ctx *SimpleVarStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
 }
diff --git a/symbol.go b/symbol.go
index 308bde1..d003a70 100644
--- a/symbol.go
+++ b/symbol.go
@@ -69,9 +69,12 @@ const (
 	SymAnd
 	SymNot
 	SymComment
-	SymFunction
+	SymFuncCall
+	SymFuncDef
 	SymList
 	SymKwBut
+	SymKwFunc
+	SymExpression
 	// SymOpenComment                       //   0: '/*'
 	// SymClosedComment                     //   0: '*/'
 	// SymOneLineComment                    //   0: '//'
@@ -82,9 +85,10 @@ var keywords map[string]Symbol
 func init() {
 	//keywords = make(map[string]Symbol)
 	keywords = map[string]Symbol{
-		"AND": SymKwAnd,
-		"BUT": SymKwBut,
-		"NOT": SymKwNot,
-		"OR":  SymKwOr,
+		"AND":  SymKwAnd,
+		"BUT":  SymKwBut,
+		"FUNC": SymKwFunc,
+		"NOT":  SymKwNot,
+		"OR":   SymKwOr,
 	}
 }
diff --git a/term.go b/term.go
index 7703cef..52e0082 100644
--- a/term.go
+++ b/term.go
@@ -5,7 +5,6 @@
 package expr
 
 import (
-	"fmt"
 	"strings"
 )
 
@@ -146,14 +145,6 @@ func (self *term) isLeaf() bool {
 	return self.position == posLeaf
 }
 
-// func (self *term) getKind() termKind {
-// 	return self.kind
-// }
-
-// func (self *term) getClass() termClass {
-// 	return self.class
-// }
-
 func (self *term) getPriority() termPriority {
 	return self.priority
 }
@@ -165,21 +156,17 @@ func (self *term) setParent(parent *term) {
 	}
 }
 
-// func (self *term) isOperand() bool {
-// 	return self.getClass() != classOperator
-// }
-
-// func (self *term) isOperator() bool {
-// 	return self.getClass() == classOperator
-// }
-
 func (self *term) source() string {
 	return self.tk.source
 }
 
+func (self *term) value() any {
+	return self.tk.Value
+}
+
 func (self *term) compute(ctx exprContext) (v any, err error) {
 	if self.evalFunc == nil {
-		err = fmt.Errorf("undefined eval-func for %v term type", self.kind)
+		err = self.tk.Errorf("undefined eval-func for %v term type", self.kind)
 	} else {
 		v, err = self.evalFunc(ctx, self)
 	}
@@ -187,7 +174,7 @@ func (self *term) compute(ctx exprContext) (v any, err error) {
 }
 
 func (self *term) errIncompatibleTypes(leftValue, rightValue any) error {
-	return fmt.Errorf(
+	return self.tk.Errorf(
 		"left operand '%v' [%T] and right operand '%v' [%T] are not compatible with operator %q",
 		leftValue, leftValue,
 		rightValue, rightValue,
@@ -195,23 +182,29 @@ func (self *term) errIncompatibleTypes(leftValue, rightValue any) error {
 }
 
 func (self *term) errIncompatibleType(value any) error {
-	return fmt.Errorf(
-		"prefix/postfix operator %q do not support operand '%v' [%T]", self.source(), value, value)
+	return self.tk.Errorf(
+		"prefix/postfix operator %q do not support operand '%v' [%T]",
+		self.source(), value, value)
+}
+
+func (self *term) Errorf(template string, args ...any) (err error) {
+	err = self.tk.Errorf(template, args...)
+	return
 }
 
 func (self *term) checkOperands() (err error) {
 	switch self.position {
 	case posInfix:
 		if self.children == nil || len(self.children) != 2 || self.children[0] == nil || self.children[1] == nil {
-			err = fmt.Errorf("infix operator %q requires two operands, got %d", self.source(), self.getChildrenCount())
+			err = self.tk.Errorf("infix operator %q requires two operands, got %d", self.source(), self.getChildrenCount())
 		}
 	case posPrefix:
 		if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
-			err = fmt.Errorf("prefix operator %q requires one operand", self.tk.String())
+			err = self.tk.Errorf("prefix operator %q requires one operand", self.tk.String())
 		}
 	case posPostfix:
 		if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
-			err = fmt.Errorf("postfix operator %q requires one operand", self.tk.String())
+			err = self.tk.Errorf("postfix operator %q requires one operand", self.tk.String())
 		}
 	}
 	return
diff --git a/term_test.go b/term_test.go
index ee023ae..8bcfd76 100644
--- a/term_test.go
+++ b/term_test.go
@@ -10,9 +10,9 @@ import (
 )
 
 func TestString(t *testing.T) {
-	tk1 := NewValueToken(SymInteger, "100", 100)
-	tk2 := NewToken(SymPlus, "+")
-	tk3 := NewValueToken(SymInteger, "50", 500)
+	tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
+	tk2 := NewToken(0, 0, SymPlus, "+")
+	tk3 := NewValueToken(0, 0, SymInteger, "50", 500)
 
 	tree := NewAst()
 	if gotErr := tree.addTokens(tk1, tk2, tk3); gotErr == nil {
@@ -23,7 +23,7 @@ func TestString(t *testing.T) {
 }
 
 func TestGetRoom(t *testing.T) {
-	tk1 := NewValueToken(SymInteger, "100", 100)
+	tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
 
 	tree := NewAst()
 	if gotErr := tree.addTokens(tk1); gotErr == nil {
@@ -33,7 +33,7 @@ func TestGetRoom(t *testing.T) {
 	}
 }
 func TestGetChildrenCount(t *testing.T) {
-	tk1 := NewValueToken(SymInteger, "100", 100)
+	tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
 
 	tree := NewAst()
 	if gotErr := tree.addTokens(tk1); gotErr == nil {
diff --git a/token.go b/token.go
index a159168..cd6ec3f 100644
--- a/token.go
+++ b/token.go
@@ -11,6 +11,8 @@ import (
 )
 
 type Token struct {
+	row    int
+	col    int
 	Sym    Symbol
 	source string
 	Value  any
@@ -30,19 +32,19 @@ func (tk *Token) String() string {
 	return fmt.Sprintf("%s", tk.source)
 }
 
-func NewToken(sym Symbol, source string) *Token {
-	return &Token{Sym: sym, source: source}
+func NewToken(row, col int, sym Symbol, source string) *Token {
+	return &Token{row: row, col: col, Sym: sym, source: source}
 }
 
-func NewValueToken(sym Symbol, source string, value any) *Token {
-	return &Token{Sym: sym, source: source, Value: value}
+func NewValueToken(row, col int, sym Symbol, source string, value any) *Token {
+	return &Token{row: row, col: col, Sym: sym, source: source, Value: value}
 }
 
 func NewErrorToken(row, col int, err error) *Token {
 	if err == io.EOF {
-		return NewToken(SymEos, "")
+		return NewToken(row, col, SymEos, "")
 	}
-	return NewValueToken(SymError, fmt.Sprintf("[%d:%d]", row, col), err)
+	return NewValueToken(row, col, SymError, fmt.Sprintf("[%d:%d]", row, col), err)
 }
 
 func (tk *Token) IsEos() bool {
@@ -56,3 +58,8 @@ func (tk *Token) IsError() bool {
 func (tk *Token) IsTerm(termSymbols []Symbol) bool {
 	return tk.IsEos() || tk.IsError() || (termSymbols != nil && slices.Index(termSymbols, tk.Sym) >= 0)
 }
+
+func (self *Token) Errorf(template string, args ...any) (err error) {
+	err = fmt.Errorf(fmt.Sprintf("[%d:%d] ", self.row, self.col)+template, args...)
+	return
+}
diff --git a/token_test.go b/token_test.go
index 0e58d20..35aa0bc 100644
--- a/token_test.go
+++ b/token_test.go
@@ -10,8 +10,8 @@ import (
 )
 
 func TestDevString(t *testing.T) {
-	tk1 := NewValueToken(SymInteger, "100", 100)
-	tk2 := NewToken(SymPlus, "+")
+	tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
+	tk2 := NewToken(0, 0, SymPlus, "+")
 
 	fmt.Println("Token '100':", tk1.DevString())
 	fmt.Println("Token '+':", tk2.DevString())
diff --git a/utils.go b/utils.go
index 8989670..ca7e314 100644
--- a/utils.go
+++ b/utils.go
@@ -101,3 +101,15 @@ func anyFloat(v any) (float float64, ok bool) {
 	}
 	return
 }
+
+func CopyMap[K comparable, V any](dest, source map[K]V) map[K]V {
+	for k, v := range source {
+		dest[k] = v
+	}
+	return dest
+}
+
+func CloneMap[K comparable, V any](source map[K]V) map[K]V {
+	dest := make(map[K]V, len(source))
+	return CopyMap(dest, source)
+}