From 8a9870ed59225972de389b7b4a494a57390bff1b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 9 Sep 2015 14:51:48 +0200 Subject: Add initial support for function calls: $func(a b c) Now it is just a stub that prints the function name and its argument. Currently only single argument can be passed (no value pack support yet). --- build/parser.cxx | 86 +++++++++++++++++++++++++++++-------------- tests/eval/buildfile | 1 + tests/function/call/buildfile | 15 ++++++++ tests/function/call/test.out | 7 ++++ tests/function/call/test.sh | 3 ++ 5 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 tests/function/call/buildfile create mode 100644 tests/function/call/test.out create mode 100755 tests/function/call/test.sh diff --git a/build/parser.cxx b/build/parser.cxx index d68bcd9..42b9a98 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -401,6 +401,14 @@ namespace build continue; } + // Allow things like function calls that don't result in anything. + // + if (tt == type::newline && ns.empty ()) + { + next (t, tt); + continue; + } + fail (t) << "unexpected " << t; } } @@ -1034,7 +1042,7 @@ namespace build // pretty quickly end up with a list of names that we need // to splice into the result. // - names_type lv_eval; + names_type lv_data; const names_type* plv; location loc; @@ -1063,58 +1071,82 @@ namespace build // Make sure the result of evaluation is a single, simple name. // if (ns.size () != 1 || !ns.front ().simple ()) - fail (loc) << "variable name expected instead of '" << ns << "'"; + fail (loc) << "variable/function name expected instead of '" + << ns << "'"; n = move (ns.front ().value); } else - fail (t) << "variable name expected instead of " << t; + fail (t) << "variable/function name expected instead of " << t; if (n.empty ()) - fail (loc) << "empty variable name"; + fail (loc) << "empty variable/function name"; - // Process variable name. + // Figure out whether this is a variable expansion of a function + // call. // - if (n.front () == '.') // Fully qualified name. - n.erase (0, 1); - else + tt = peek (); + + if (tt == type::lparen) { - //@@ TODO: append namespace if any. - } + next (t, tt); // Get '('. + names_type ns (eval (t, tt)); - // Lookup. - // - const auto& var (variable_pool.find (move (n))); - auto l (target_ != nullptr ? (*target_)[var] : (*scope_)[var]); + // Just a stub for now. + // + cout << n << "(" << ns << ")" << endl; - // Undefined/NULL namespace variables are not allowed. - // - if (!l && var.name.find ('.') != string::npos) - fail (loc) << "undefined/null namespace variable " << var.name; + tt = peek (); - tt = peek (); + if (lv_data.empty ()) + continue; - if (!l || l->empty ()) - continue; + plv = &lv_data; + what = "function call"; + } + else + { + // Process variable name. + // + if (n.front () == '.') // Fully qualified name. + n.erase (0, 1); + else + { + //@@ TODO: append namespace if any. + } + + // Lookup. + // + const auto& var (variable_pool.find (move (n))); + auto l (target_ != nullptr ? (*target_)[var] : (*scope_)[var]); - plv = &l->data_; - what = "variable expansion"; + // Undefined/NULL namespace variables are not allowed. + // + if (!l && var.name.find ('.') != string::npos) + fail (loc) << "undefined/null namespace variable " << var.name; + + if (!l || l->empty ()) + continue; + + plv = &l->data_; + what = "variable expansion"; + } } else { loc = get_location (t, &path_); - lv_eval = eval (t, tt); + lv_data = eval (t, tt); tt = peek (); - if (lv_eval.empty ()) + if (lv_data.empty ()) continue; - plv = &lv_eval; + plv = &lv_data; what = "context evaluation"; } - // @@ Could move if (lv == &lv_eval). + // @@ Could move if (lv == &lv_data). // const names_type& lv (*plv); diff --git a/tests/eval/buildfile b/tests/eval/buildfile index c658d3b..cf315b6 100644 --- a/tests/eval/buildfile +++ b/tests/eval/buildfile @@ -1,4 +1,5 @@ (./): +() # Invalid. # diff --git a/tests/function/call/buildfile b/tests/function/call/buildfile new file mode 100644 index 0000000..93eba14 --- /dev/null +++ b/tests/function/call/buildfile @@ -0,0 +1,15 @@ +$identity() +$identity (a) +$identity (a b c) +$identity(sub/dir{x y z}) + +# Verify we can inhibit function call with quoting. +# +foo = FOO +bar = BAR + +print $foo"($bar)" +print "$foo"($bar) +print "$foo""($bar)" + +./: diff --git a/tests/function/call/test.out b/tests/function/call/test.out new file mode 100644 index 0000000..abc5974 --- /dev/null +++ b/tests/function/call/test.out @@ -0,0 +1,7 @@ +identity() +identity(a) +identity(a b c) +identity(sub/dir{x} sub/dir{y} sub/dir{z}) +FOOBAR +FOOBAR +FOOBAR diff --git a/tests/function/call/test.sh b/tests/function/call/test.sh new file mode 100755 index 0000000..b898b3c --- /dev/null +++ b/tests/function/call/test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind -q b -q | diff -u test.out - -- cgit v1.1