-module(yaml_parser_utils). -export([ read_file/1, get_decorator/2, get_decorators/2, get_context/3, parse_args/2 ]). -include("../bt_node_behaviours/bt_nodes.hrl"). %% convert yaml file to dictionary %% TODO: parse in detailed mode so better errors can be reported, which include line numbers read_file(YAMLFilePath) -> [YAMLList] = yamerl_constr:file(YAMLFilePath), maps:from_list(YAMLList). %% merge local bb keys with rest of context %% local bb key => get_bb_key(local bb key) get_context(Context, _Namespace, []) -> Context; get_context(PartialContext, Namespace, [LocalBBKey | Rest]) -> NewPartialContext = maps:put(LocalBBKey, bt_blackboard:get_bb_key(Namespace, LocalBBKey), PartialContext), get_context(NewPartialContext, Namespace, Rest). get_decorator(DecoratorList, Context) -> Module = proplists:get_value("module", DecoratorList), UnparsedArgs = proplists:get_value("args", DecoratorList), Name = proplists:get_value("name", DecoratorList, Module), % Params = proplists:get_value("params", DecoratorList, []), ModuleAtom = list_to_atom(Module), Params = ModuleAtom:get_params(), bt_parser_utils:throw_error_if_args_and_params_dont_match(Module, UnparsedArgs, Params), ArgsAsMap = parse_args(UnparsedArgs, Context), #decorator{ name = Name, module = ModuleAtom, args = ArgsAsMap }. get_decorators(undefined, _Context) -> []; get_decorators(DecoratorsList, Context) -> [get_decorator(DecoratorList, Context) || DecoratorList <- DecoratorsList]. parse_args(Args, Context) -> parse_args(Args, #{}, Context). parse_args([], NewContext, _Context) -> NewContext; parse_args([{ArgKey, ArgVal} | Rest], NewContext, Context) -> %% check if arg val is in context; if so, then replace. ValToPut = parse_argval(ArgVal, Context), NewNewContext = maps:put(ArgKey, ValToPut, NewContext), parse_args(Rest, NewNewContext, Context). parse_argval(ArgVal, Context) -> case maps:is_key(ArgVal, Context) of true -> maps:get(ArgVal, Context); false -> parse_argval_basic(ArgVal, Context) end. %% can be deeply nested! %% flawed logic because can't really detect if a list is string or not... but maybe don't need to? parse_argval_basic(ArgVal, _Context) when is_atom(ArgVal); is_number(ArgVal); is_binary(ArgVal) -> ArgVal; parse_argval_basic(ArgVal, Context) when is_tuple(ArgVal) -> %% split L = tuple_to_list(ArgVal), list_to_tuple(parse_argval_basic(L, Context)); parse_argval_basic(ArgVal, Context) when is_list(ArgVal) -> [parse_argval(X, Context) || X <- ArgVal].