diff --git a/parser/nodes.cc b/parser/nodes.cc index 2584bb9..f4331e4 100644 --- a/parser/nodes.cc +++ b/parser/nodes.cc @@ -1,14 +1,53 @@ #include +#include #include #include #include +#include #include "nodes.h" using namespace std; +typedef NodeRef (*Function)(NodeRef args); + +NodeRef CosFunction(NodeRef args); +NodeRef SinFunction(NodeRef args); +NodeRef SqrtFunction(NodeRef args); +NodeRef AbsFunction(NodeRef args); + +static const struct { + const char * fn_name; + Function fn; +} functions[] = { + {"cos", CosFunction}, + {"sin", SinFunction}, + {"sqrt", SqrtFunction}, + {"abs", AbsFunction} +}; + +class FunctionMap : public map +{ + public: + FunctionMap() + { + for (unsigned int i = 0; + i < sizeof(functions)/sizeof(functions[0]); + i++) + { + (*this)[functions[i].fn_name] = functions[i].fn; + } + } + bool contains(const string & key) + { + return find(key) != end(); + } +}; + +static FunctionMap function_map; + void Node::evaluateChildren(refptr parent) { /* recursively evaluate all children nodes */ @@ -169,3 +208,59 @@ NodeRef ElseNode::evaluate() evaluateChildren(eval); return eval; } + +NodeRef FunctionCallNode::evaluate() +{ + if (function_map.contains(m_name->getString())) + { + return function_map[m_name->getString()](m_parameters); + } + cerr << "Error: no function \"" << m_name->getString() << "\" defined!" + << endl; + exit(4); +} + + +/************************************************************************** + * Scene file functions * + *************************************************************************/ +NodeRef CosFunction(NodeRef args) +{ + if (args->getChildren().size() != 1) + { + cerr << "Error: cos function requires 1 argument" << endl; + exit(4); + } + return new NumberNode(cos(args->getChildren()[0]->evaluate()->getNumber())); +} + +NodeRef SinFunction(NodeRef args) +{ + if (args->getChildren().size() != 1) + { + cerr << "Error: sin function requires 1 argument" << endl; + exit(4); + } + return new NumberNode(sin(args->getChildren()[0]->evaluate()->getNumber())); +} + +NodeRef SqrtFunction(NodeRef args) +{ + if (args->getChildren().size() != 1) + { + cerr << "Error: sqrt function requires 1 argument" << endl; + exit(4); + } + return new NumberNode(sqrt(args->getChildren()[0]->evaluate()->getNumber())); +} + +NodeRef AbsFunction(NodeRef args) +{ + if (args->getChildren().size() != 1) + { + cerr << "Error: abs function requires 1 argument" << endl; + exit(4); + } + return new NumberNode(fabs(args->getChildren()[0]->evaluate()->getNumber())); +} + diff --git a/parser/nodes.h b/parser/nodes.h index e0c865d..d949e1d 100644 --- a/parser/nodes.h +++ b/parser/nodes.h @@ -750,6 +750,19 @@ class ElseNode : public Node virtual NodeRef evaluate(); }; +class FunctionCallNode : public Node +{ + public: + FunctionCallNode(NodeRef name, NodeRef parameters) + { + m_name = name; + m_parameters = parameters; + } + virtual NodeRef evaluate(); + protected: + NodeRef m_name, m_parameters; +}; + /* this class is only used to hold a set of items coming out of a class's * evaluate() from above. the evaluateChildren() top-level method will * propagate children of this class up to the level of their parent */ diff --git a/parser/parser.yy b/parser/parser.yy index 6385174..b4664f1 100644 --- a/parser/parser.yy +++ b/parser/parser.yy @@ -358,6 +358,7 @@ expression: term { $$ = $1; } $$ = new BinOpNode('-', new NumberNode(0.0), $2); } | stmt_expression { $$ = $1; } + | function_call { $$ = $1; } ; maybe_expression: /* empty */ @@ -439,6 +440,28 @@ if_more: /* empty */ $$->addChildren($3); } ; + +function_call: IDENTIFIER LPAREN function_call_parameters RPAREN { + $$ = new FunctionCallNode($1, $3); + } + ; + +function_call_parameters: /* empty */ + | expression function_call_more_parameters { + $$ = new ItemsNode(); + $$->addChild($1); + $$->addChildren($2); + } + ; + +function_call_more_parameters: /* empty */ + | COMMA expression function_call_more_parameters { + $$ = new ItemsNode(); + $$->addChild($2); + $$->addChildren($3); + } + ; + %% refptr parse(const char * fileName, refptr scope) diff --git a/scenes/if-test.fart b/scenes/if-test.fart index 99786cc..400a4eb 100644 --- a/scenes/if-test.fart +++ b/scenes/if-test.fart @@ -44,7 +44,11 @@ scene } else { - material mat3 + material + { + color <1, 0, 0> + transparency abs($x / 120) + } } } $m := $m + 1