diff --git a/plugins/yanger_yin.erl b/plugins/yanger_yin.erl
new file mode 100644
index 0000000..cdd91c0
--- /dev/null
+++ b/plugins/yanger_yin.erl
@@ -0,0 +1,414 @@
+%%%----------------------------------------------------------------%%%
+%%% @doc Yanger Yin Plugin %%%
+%%% @author Lisa Bevemyr, lbevemyr@cisco.com (summer intern 2021) %%%
+%%% Prints YIN from a YANG model according to the rules in RFC %%%
+%%% 7950. Inspiration for this plugin came from a the similar %%%
+%%% plugin for Pyang and the YANG plugin for Yanger. %%%
+%%%----------------------------------------------------------------%%%
+
+-module(yanger_yin).
+-behaviour(yanger_plugin).
+
+-export([init/1]).
+
+-include_lib("yanger/include/yang.hrl").
+
+-spec help() -> binary().
+help() ->
+ <<"Translates a YANG module to YIN \n\n"
+ "The following options can be used to modify the output:\n\n"
+ " --yin-canonical Will sort the output in canonical order.\n"
+ " --yin-pretty-strings Texts will be printed on multiple lines.\n"
+ >>.
+init(Ctx0) ->
+ Ctx1 = yanger_plugin:register_output_format(Ctx0, yin, fun emit/3),
+ Ctx2 = yanger_plugin:register_hook(
+ Ctx1, #hooks.post_init_ctx, fun post_init_ctx/1),
+ Ctx3 = yanger_plugin:register_option_specs(Ctx2, opts()),
+ Ctx3.
+
+opts() ->
+ [{"YANG output specific options:",
+ [{yin_canonical, undefined, "yin-canonical", {boolean, false},
+ "Print in canonical order"},
+ {yin_comment, undefined, "yin-pretty-strings", {boolean, false},
+ "Pretty print strings"},
+ {yin_help, undefined, "yin-help", boolean,
+ "Prints help on YIN plugin"}
+ ]}].
+
+-record(state, {module,
+ module_prefixes,
+ outf,
+ canonical = false,
+ pretty_strings = false,
+ columns = 80,
+ rps,
+ yin_map,
+ ctx,
+ order_map = #{}
+ }).
+
+post_init_ctx(Ctx) ->
+ case proplists:get_value(yin_help, Ctx#yctx.options, false) of
+ true ->
+ io:put_chars(help()),
+ halt();
+ false ->
+ ok
+ end,
+ Ctx.
+
+-spec emit(Ctx::#yctx{}, [Modules::#module{}], Fd::io:device()) -> [].
+emit(Ctx, Modules, Fd) ->
+ OutF = fun (Str) -> file:write(Fd, Str) end,
+ State =
+ #state{ outf = OutF,
+ canonical =
+ proplists:get_value(yin_canonical, Ctx#yctx.options),
+ pretty_strings =
+ proplists:get_value(yin_comment, Ctx#yctx.options),
+ rps = [{binary:compile_pattern(RP), RWith} ||
+ {RP, RWith} <- replace_patterns()],
+ yin_map = get_yin_map(),
+ ctx = Ctx
+ },
+ lists:foreach(
+ fun (M) ->
+ ModuleMap =
+ yang:map_foldl(fun (Px, '$self', Map0) ->
+ Mod = M#module.name,
+ yang:map_insert(Mod, Px, Map0);
+ (Px, Mod, Map0) ->
+ yang:map_update(Mod, Px, Map0)
+ end,
+ yang:map_new(),
+ M#module.prefix_map),
+ State1 = State#state{
+ module = M,
+ module_prefixes = ModuleMap
+ },
+ emit_module(M, State1)
+ end, Modules),
+ %% If this format plugin will need to produce warnings or errors
+ %% in the future, these warnings and errors need to be returned here.
+ Errors = [],
+ Errors.
+
+emit_module(M, State) ->
+ OutF = State#state.outf,
+ OutF(["", nl()]),
+ emit_stmts([M#module.stmt], 0, State).
+
+emit_stmts([], _Lvl, _S) ->
+ ok;
+emit_stmts([Stmt|Stmts], Lvl, S) ->
+ OutF = S#state.outf,
+ Keyword = yang:stmt_keyword(Stmt),
+ emit_stmt_keyword(Keyword, Lvl, S),
+ YinElement = emit_stmt_arg(yang:stmt_arg(Stmt), Lvl, S, Keyword),
+ module_arg(Lvl, S, Keyword),
+ case yang:stmt_substmts(Stmt) of
+ [] when not YinElement ->
+ NewS = S,
+ OutF([fs(),ct(),nl()]);
+ SubStmts0 ->
+ OutF([ct(),nl()]),
+ {NewS, SubStmts} =
+ if S#state.canonical ->
+ sort_canonical(Keyword, SubStmts0, S);
+ true ->
+ {S, SubStmts0}
+ end,
+ emit_stmts(SubStmts, Lvl+1, NewS),
+ KeywordStr = make_str(Keyword),
+ OutF([indent(Lvl),ot(),fs(),KeywordStr,ct(),nl()])
+ end,
+ emit_stmts(Stmts, Lvl, NewS).
+
+emit_stmt_keyword(Kwd, Lvl, S) ->
+ OutF = S#state.outf,
+ OutF(indent(Lvl)),
+ case Kwd of
+ {Module, Keyword} ->
+ Prefix = yang:map_get(Module, S#state.module_prefixes),
+ OutF([ot(), make_str({Prefix, Keyword})]);
+ Keyword ->
+ OutF([ot(), make_str(Keyword)])
+ end.
+
+emit_stmt_arg([], _, _, _) ->
+ false;
+emit_stmt_arg(Arg, Lvl, S, Keyword) ->
+ OutF = S#state.outf,
+ ArgStr = make_str(Arg),
+ Ctx = S#state.ctx,
+ if is_tuple(Keyword) ->
+ {Type, YinElement} = search_for_extension(Keyword, Ctx),
+ if YinElement ->
+ {Prefix, _} = Keyword,
+ TypeStr = make_str({Prefix, Type});
+ true ->
+ TypeStr = make_str(Type)
+ end;
+ true ->
+ {Type, YinElement} = maps:get(Keyword, S#state.yin_map),
+ TypeStr = make_str(Type)
+ end,
+ case YinElement of
+ true ->
+ Indent = indent(Lvl+1),
+ Strs = binary:split(
+ ArgStr, binary:compile_pattern(<<"\n">>), [global]),
+ Acc = print_yin_element(Indent, TypeStr, Strs, S),
+ OutF(Acc);
+ false ->
+ OutF([s(), TypeStr, $=, qm(),
+ escape(ArgStr, S#state.rps), qm()])
+ end,
+ YinElement.
+
+search_for_extension({Mod, Keyword}, Ctx) ->
+ {_, TargetMod} = yang:get_module(Mod, undefined, Ctx),
+ ExtensionMap = yang:map_get(Keyword, TargetMod#module.extensions),
+ {extension, Keyword, _Pos, Substmt} = ExtensionMap#extension.stmt,
+ case yang:search_one_stmt('argument', Substmt) of
+ {argument,Type,_,ArgSubstmt} ->
+ case yang:search_one_stmt('yin-element', ArgSubstmt) of
+ {'yin-element', Bool,_,_} ->
+ {Type, Bool};
+ false ->
+ {Type, false}
+ end;
+ false ->
+ {undefined, false}
+ end.
+
+print_yin_element(Indent, TypeStr, [Str1|Strs], S) ->
+ Pretty = S#state.pretty_strings,
+ case Pretty of
+ true ->
+ Acc = [ct(),nl(), Indent, ot(), TypeStr, ct(),nl(), Indent, s(),s(),
+ escape(Str1, S#state.rps)];
+ false ->
+ Acc = [ct(), nl(), Indent, ot(), TypeStr, ct(),
+ escape(Str1, S#state.rps)]
+ end,
+ print_yin_element1(Indent, TypeStr, Strs, S, Pretty, Acc).
+
+print_yin_element1(Indent, TypeStr, [], _S, true = _Pretty, Acc) ->
+ [Acc, nl(), Indent, ot(), fs(), TypeStr];
+
+print_yin_element1(_Indent, TypeStr, [], _S, false = _Pretty, Acc) ->
+ [Acc, ot(), fs(), TypeStr];
+
+print_yin_element1(Indent, TypeStr, [Str1|Strs], S, Pretty, Acc) ->
+ Acc1 = [Acc, nl(), escape(Str1, S#state.rps)],
+ print_yin_element1(Indent, TypeStr, Strs, S, Pretty, Acc1).
+
+module_arg(Lvl, S, Module) when Module == module orelse Module == submodule ->
+ Mod = S#state.module,
+ Ctx = S#state.ctx,
+ OutF = S#state.outf,
+ Indent = case Module of
+ module -> indent(Lvl+4);
+ submodule -> indent(Lvl+5,1)
+ end,
+ OutF([nl(), Indent, "xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\""]),
+ Namespace = search_for_namespace(Mod#module.namespace, Mod, Ctx),
+ NamespaceStr = make_str(Namespace),
+ PrefixStr = make_str(Mod#module.prefix),
+ case Namespace of
+ undefined ->
+ skip;
+ _ ->
+ OutF([nl(), Indent, "xmlns:", PrefixStr, $=,
+ qm(), NamespaceStr, qm()])
+ end,
+ Imports = Mod#module.imports,
+ module_arg_imports(S, Ctx, Imports, Indent);
+
+module_arg(_Lvl, _S, _) -> skip.
+
+search_for_namespace(undefined, Mod, Ctx) ->
+ {_, TargetName} = Mod#module.xpath_ns_map,
+ Target = yang:search_module(Ctx, TargetName, undefined),
+ case Target of
+ {true, _, TargetMod} ->
+ make_str(TargetMod#module.namespace);
+ _ ->
+ undefined
+ end;
+
+search_for_namespace(Namespace, _Mod, _Ctx) ->
+ Namespace.
+
+module_arg_imports(_S, _Ctx, [], _Indent) ->
+ skip;
+module_arg_imports(S, Ctx, [Import|Imports], Indent) ->
+ OutF = S#state.outf,
+ {Namespace, _, Prefix, _} = Import,
+ PrefixStr = make_str(Prefix),
+ {_Value, TargetM} = yang:get_module(Namespace, undefined, Ctx),
+ TargetMNamespaceStr = make_str(TargetM#module.namespace),
+ OutF([nl(), Indent, "xmlns:", PrefixStr, $=,
+ qm(), TargetMNamespaceStr, qm()]),
+ module_arg_imports(S, Ctx, Imports, Indent).
+
+sort_canonical(Keyword, SubStmts, S) ->
+ OrderMap = S#state.order_map,
+ case maps:get(Keyword, OrderMap, undefined) of
+ undefined ->
+ case yang_parser:get_statement_spec(Keyword) of
+ {value, {_, _, Rules, _}} ->
+ NewOrderMap = maps:put(Keyword, mk_order(Rules), OrderMap),
+ NewS = S#state{order_map = NewOrderMap},
+ sort_canonical(Keyword, SubStmts, NewS);
+ _ ->
+ {S, SubStmts}
+ end;
+ Order ->
+ {S, lists:sort(
+ fun(A, B) ->
+ ordinal(yang:stmt_keyword(A), Order) =<
+ ordinal(yang:stmt_keyword(B), Order)
+ end, SubStmts)}
+ end.
+
+mk_order(Rules) ->
+ mk_order0(Rules, 0, gb_trees:empty()).
+
+mk_order0([{'$cut', _} | T], N, Tree) ->
+ mk_order0(T, N+1, Tree);
+mk_order0([{Keyword, '?'} | T], N, Tree) ->
+ mk_order0(T, N+1, gb_trees:enter(Keyword, N, Tree));
+mk_order0([{Keyword, '1'} | T], N, Tree) ->
+ mk_order0(T, N+1, gb_trees:enter(Keyword, N, Tree));
+mk_order0([{Keyword, '*'} | T], N, Tree) ->
+ mk_order0(T, N, gb_trees:enter(Keyword, N, Tree));
+
+mk_order0([], _, Tree) ->
+ Tree.
+
+ordinal(Keyword, Order) ->
+ case gb_trees:lookup(Keyword, Order) of
+ {value, N} ->
+ N;
+ _ ->
+ undefined
+ end.
+
+s() -> $\ .
+nl() -> $\n.
+ot() -> $<.
+fs() -> $/.
+ct() -> $>.
+qm() -> $".
+
+indent(Lvl) -> lists:duplicate(Lvl*2, s()).
+indent(Lvl,1) -> C = Lvl*2+1, lists:duplicate(C, s()).
+
+make_str({Prefix, Name}) ->
+ iolist_to_binary([make_str(Prefix), ":", make_str(Name)]);
+make_str(A) when is_atom(A) ->
+ atom_to_binary(A, unicode);
+make_str(Str) when is_binary(Str) ->
+ Str;
+make_str(Int) when is_integer(Int) ->
+ integer_to_binary(Int);
+make_str(Str) when is_list(Str) ->
+ iolist_to_binary(Str).
+
+escape(BStr, RPs) ->
+ lists:foldl(
+ fun({RPq, RWith}, BStr1) ->
+ binary:replace(BStr1, RPq, RWith, [global])
+ end, BStr, RPs).
+
+replace_patterns() ->
+ [{<<"\\">>, <<"\\\\">>},
+ {<<"\"">>, <<"\\\"">>},
+ {<<"\t">>, <<"\\t">>},
+ {<<"&">>, <<"&">>},
+ {<<"<">>, <<"<">>},
+ {<<">">>, <<"≷">>},
+ {<<"\"">>, <<""">>},
+ {<<"'">>, <<"'">>}].
+
+
+
+%% Mapping of statements to the YIN representation of their arguments.
+%% The values are pairs whose first component specifies whether the
+%% argument is stored in a subelement and the second component is the
+%% name of the attribute or subelement carrying the argument. See YANG
+%% specification.
+get_yin_map() ->
+ #{'action'=> {'name', false},
+ 'anydata'=> {'name', false},
+ 'anyxml'=> {'name', false},
+ 'argument'=> {'name', false},
+ 'augment'=> {'target-node', false},
+ 'base'=> {'name', false},
+ 'belongs-to'=> {'module', false},
+ 'bit'=> {'name', false},
+ 'case'=> {'name', false},
+ 'choice'=> {'name', false},
+ 'config'=> {'value', false},
+ 'contact'=> {'text', true},
+ 'container'=> {'name', false},
+ 'default'=> {'value', false},
+ 'description'=> {'text', true},
+ 'deviate'=> {'value', false},
+ 'deviation'=> {'target-node', false},
+ 'enum'=> {'name', false},
+ 'error-app-tag'=> {'value', false},
+ 'error-message'=> {'value', true},
+ 'extension'=> {'name', false},
+ 'feature'=> {'name', false},
+ 'fraction-digits'=> {'value', false},
+ 'grouping'=> {'name', false},
+ 'identity'=> {'name', false},
+ 'if-feature'=> {'name', false},
+ 'import'=> {'module', false},
+ 'include'=> {'module', false},
+ 'input'=> {undefined, undefined},
+ 'key'=> {'value', false},
+ 'leaf'=> {'name', false},
+ 'leaf-list'=> {'name', false},
+ 'length'=> {'value', false},
+ 'list'=> {'name', false},
+ 'mandatory'=> {'value', false},
+ 'max-elements'=> {'value', false},
+ 'min-elements'=> {'value', false},
+ 'modifier'=> {'value', false},
+ 'module'=> {'name', false},
+ 'must'=> {'condition', false},
+ 'namespace'=> {'uri', false},
+ 'notification'=> {'name', false},
+ 'ordered-by'=> {'value', false},
+ 'organization'=> {'text', true},
+ 'output'=> {undefined, undefined},
+ 'path'=> {'value', false},
+ 'pattern'=> {'value', false},
+ 'position'=> {'value', false},
+ 'presence'=> {'value', false},
+ 'prefix'=> {'value', false},
+ 'range'=> {'value', false},
+ 'reference'=> {'text', true},
+ 'refine'=> {'target-node', false},
+ 'require-instance'=>{'value', false},
+ 'revision'=> {'date', false},
+ 'revision-date'=> {'date', false},
+ 'rpc'=> {'name', false},
+ 'status'=> {'value', false},
+ 'submodule'=> {'name', false},
+ 'type'=> {'name', false},
+ 'typedef'=> {'name', false},
+ 'unique'=> {'tag', false},
+ 'units'=> {'name', false},
+ 'uses'=> {'name', false},
+ 'value'=> {'value', false},
+ 'when'=> {'condition', false},
+ 'yang-version'=> {'value', false},
+ 'yin-element'=> {'value', false}
+ }.
diff --git a/test/lux/yin/Makefile b/test/lux/yin/Makefile
new file mode 100644
index 0000000..e106e8a
--- /dev/null
+++ b/test/lux/yin/Makefile
@@ -0,0 +1,8 @@
+include ../../support/*_testcases.mk
+
+build:
+
+clean:
+ rm -rf lux_logs _tmp_*
+
+.PHONY: build clean
diff --git a/test/lux/yin/parent.yang b/test/lux/yin/parent.yang
new file mode 100644
index 0000000..0ffdd6f
--- /dev/null
+++ b/test/lux/yin/parent.yang
@@ -0,0 +1,11 @@
+module parent {
+ namespace urn:parent;
+ prefix parent;
+
+ container parent-container {
+ // to be augmented by small6
+ }
+ container parent-container-2 {
+ // to be augmented by small6
+ }
+}
diff --git a/test/lux/yin/small6.yang b/test/lux/yin/small6.yang
new file mode 100644
index 0000000..cc73e68
--- /dev/null
+++ b/test/lux/yin/small6.yang
@@ -0,0 +1,36 @@
+module small6 {
+ namespace urn:r;
+ prefix rprefix;
+
+ import parent {
+ prefix parentPrefix;
+ }
+
+ augment "/parentPrefix:parent-container" {
+ list test-list {
+ key test-key;
+
+ leaf test-key {
+ type string;
+ }
+
+ leaf dummy {
+ type uint16;
+ }
+ }
+ }
+
+ augment "/parentPrefix:parent-container-2" {
+ list test-list {
+ key test-key;
+
+ leaf test-key {
+ type string;
+ }
+
+ leaf dummy {
+ type uint16;
+ }
+ }
+ }
+}
diff --git a/test/lux/yin/test_good/a.yang b/test/lux/yin/test_good/a.yang
new file mode 100644
index 0000000..cc55a8b
--- /dev/null
+++ b/test/lux/yin/test_good/a.yang
@@ -0,0 +1,30 @@
+module a {
+ namespace "urn:a";
+ prefix a;
+
+ grouping a {
+ leaf a {
+ type leafref {
+ path "/a:x/a:y/a:k1";
+ }
+ }
+ leaf b {
+ type leafref {
+ path "deref(../a)/../a:k2";
+// path "/a:x/a:y[a:k1 = current()/../a]/a:k2";
+ }
+ }
+ }
+
+ container x {
+ list y {
+ key "k1 k2";
+ leaf k1 {
+ type string;
+ }
+ leaf k2 {
+ type string;
+ }
+ }
+ }
+}
diff --git a/test/lux/yin/test_good/b.yang b/test/lux/yin/test_good/b.yang
new file mode 100644
index 0000000..418dcea
--- /dev/null
+++ b/test/lux/yin/test_good/b.yang
@@ -0,0 +1,12 @@
+module b {
+ namespace "urn:b";
+ prefix b;
+
+ import a {
+ prefix a;
+ }
+
+ container z {
+ uses a:a;
+ }
+}
\ No newline at end of file
diff --git a/test/lux/yin/test_good/q.yang b/test/lux/yin/test_good/q.yang
new file mode 100644
index 0000000..bb50bad
--- /dev/null
+++ b/test/lux/yin/test_good/q.yang
@@ -0,0 +1,6 @@
+module q {
+ namespace urn:q;
+ prefix q;
+
+ include qs;
+}
diff --git a/test/lux/yin/test_good/qs.yang b/test/lux/yin/test_good/qs.yang
new file mode 100644
index 0000000..8fb625b
--- /dev/null
+++ b/test/lux/yin/test_good/qs.yang
@@ -0,0 +1,20 @@
+submodule qs {
+ belongs-to q {
+ prefix q;
+ }
+
+ extension foo {
+ argument id;
+ }
+
+ identity foo;
+
+ feature foo;
+
+ grouping g {
+ leaf x {
+ type string;
+ }
+ }
+
+}
diff --git a/test/lux/yin/test_good/w.yang b/test/lux/yin/test_good/w.yang
new file mode 100644
index 0000000..f7baddf
--- /dev/null
+++ b/test/lux/yin/test_good/w.yang
@@ -0,0 +1,42 @@
+module w {
+ namespace urn:w;
+ prefix w;
+
+ import q {
+ prefix qq;
+ }
+
+ identity g {
+ base qq:foo;
+ }
+
+ grouping X {
+ leaf y {
+ qq:foo 42;
+ type uint32;
+ }
+ }
+
+ grouping Y {
+ container z {
+ if-feature qq:foo;
+ uses X;
+ }
+ }
+ uses Y {
+ refine z/y {
+ default 42;
+ }
+ }
+
+ container q {
+ uses qq:g;
+ }
+ leaf t {
+ type leafref {
+ path "/q/x";
+ }
+ }
+
+
+}
diff --git a/test/lux/yin/test_good/xt10.yang b/test/lux/yin/test_good/xt10.yang
new file mode 100644
index 0000000..f183f78
--- /dev/null
+++ b/test/lux/yin/test_good/xt10.yang
@@ -0,0 +1,15 @@
+module xt10 {
+ namespace "urn:xt10";
+ prefix "xt10";
+
+ typedef a {
+ type string;
+ }
+
+ leaf x {
+ type decimal64 {
+ fraction-digits 1;
+ range "-6.3..0.0";
+ }
+ }
+}
diff --git a/test/lux/yin/test_good/xt5.yang b/test/lux/yin/test_good/xt5.yang
new file mode 100644
index 0000000..72042e4
--- /dev/null
+++ b/test/lux/yin/test_good/xt5.yang
@@ -0,0 +1,28 @@
+module xt5 {
+
+ namespace "urn:test:xt5";
+ prefix xt5;
+
+ grouping x {
+ leaf foo { type empty; mandatory true; }
+ }
+
+ typedef xc {
+ type int32;
+ }
+
+ extension x {
+ argument name;
+ }
+
+ leaf foo { type int16; }
+
+
+ extension foo {
+ argument bar {
+ yin-element true;
+ }
+ }
+
+
+}
diff --git a/test/lux/yin/test_good/xt6.yang b/test/lux/yin/test_good/xt6.yang
new file mode 100644
index 0000000..07f8ab1
--- /dev/null
+++ b/test/lux/yin/test_good/xt6.yang
@@ -0,0 +1,18 @@
+module xt6 {
+
+ namespace "urn:test:xt6";
+ prefix xt6;
+
+ import xt5 {
+ prefix xt5;
+ }
+
+ uses xt5:x;
+
+ xt5:foo "barbar";
+
+ leaf y {
+ type xt5:xc;
+ }
+
+}
diff --git a/test/lux/yin/test_good/xt7.yang b/test/lux/yin/test_good/xt7.yang
new file mode 100644
index 0000000..a704959
--- /dev/null
+++ b/test/lux/yin/test_good/xt7.yang
@@ -0,0 +1,29 @@
+module xt7 {
+ prefix x;
+ namespace "urn:test:xt7";
+
+ leaf foo {
+ type int16;
+ x:foo "some string";
+ }
+
+ x:foo "another string";
+
+ extension foo {
+ argument bar {
+ yin-element false;
+ }
+ }
+
+ grouping baz {
+ leaf x {
+ type int32;
+ }
+ }
+ uses baz {
+ refine x {
+ default 42;
+ }
+ }
+
+}
diff --git a/test/lux/yin/test_good/yt10.yang b/test/lux/yin/test_good/yt10.yang
new file mode 100644
index 0000000..c86e1de
--- /dev/null
+++ b/test/lux/yin/test_good/yt10.yang
@@ -0,0 +1,36 @@
+module yt10 {
+
+ namespace "urn:ietf:params:xml:ns:yang:yt10";
+
+ prefix "yt10";
+
+ import yt9 { prefix yt9; }
+
+ organization "Netconf Central";
+
+ contact "Andy Bierman";
+
+ description "YANG test module 9. augment";
+
+ revision 2008-04-11 { description "initial version"; }
+
+ augment /yt9:con1 {
+ leaf b1 { type int32; }
+
+ container con2 {
+ leaf b2 { type string; }
+ }
+ }
+
+ container test {
+ description "Particular configuration to retrieve.";
+ // mandatory true;
+ uses Foo;
+ }
+
+ grouping Foo {
+ leaf X { type int32; }
+ leaf Y { type uint32; }
+ }
+
+}
diff --git a/test/lux/yin/test_good/yt5.yang b/test/lux/yin/test_good/yt5.yang
new file mode 100644
index 0000000..e490356
--- /dev/null
+++ b/test/lux/yin/test_good/yt5.yang
@@ -0,0 +1,203 @@
+module yt5 {
+
+ namespace "urn:ietf:params:xml:ns:yang:yt5";
+ prefix "yt5";
+
+ organization
+ "YANG Language Design Team";
+
+ contact
+ "ietf@andybierman.com";
+
+ description
+ "YANG test module 5.";
+
+ revision 2008-02-12 {
+ description "Update test cases.";
+ }
+
+ revision 2007-12-26 {
+ description "Initial revision.";
+ }
+
+ grouping G_one {
+ typedef local_1 { type int32; units meters; default 0; }
+ leaf G_aaa { type int8; }
+ uses G_two;
+ leaf G_bbb { type uint8; }
+ leaf test_leaf { type local_1; }
+ }
+
+ grouping G_two {
+ typedef local_1 { type string; default fred; }
+ leaf G_ccc { type binary; }
+ container G_ddd {
+ leaf G_eee {
+ type uint8;
+ mandatory true;
+ reference "RFC 2021";
+ }
+ }
+ leaf test_leaf2 { type local_1; }
+ }
+
+ container con2 {
+
+ grouping AA {
+ leaf a { type A_typ; }
+
+ container b {
+ container bb {
+ uses AAA;
+ }
+ grouping AAA {
+// typedef B_typ { type instance-identifier; }
+ uses AAAA {
+/*
+ extend "yt5:e/yt5:f" {
+ leaf hhh { type binary; }
+ leaf h { type B_typ; }
+ }
+*/
+ }
+
+ leaf d { type int8; }
+ }
+ }
+
+ grouping AAAA {
+ container e {
+ container f {
+ typedef con2 { description "duplicate test"; type int16; }
+ leaf g { type int64; }
+ leaf h { type con2; }
+ leaf i { type con2; }
+ }
+ }
+ }
+
+ typedef A_typ {
+ type int32;
+ default 3;
+ units miles;
+ }
+
+/* not allowed anymore
+ augment b {
+ container c {
+ leaf cc { type string; }
+ }
+ }
+*/
+ }
+
+ container con3 {
+ uses AA {
+/*
+ extend "b/bb/e/f" {
+ container con4 { presence "means something"; }
+ }
+*/
+ }
+ }
+ }
+
+ container foo {
+ uses foo;
+ }
+
+ grouping foo {
+ leaf foo { type foo; }
+ }
+
+ grouping bar {
+ leaf bar { type foo; }
+ leaf-list yyy {
+ type binary;
+ min-elements 2;
+ max-elements 12;
+ }
+ leaf baz { type int16; }
+ leaf goo { type foo; }
+ container zzz {
+ leaf zzzz { type uint32; }
+ }
+ }
+
+ container foo2 {
+ typedef foobar {
+ type uint32;
+ }
+ grouping foobar {
+ leaf foo { type foo; }
+ }
+ container foo3 {
+ uses foobar;
+ leaf-list foo4 { type foobar; }
+ }
+ container foo4 {
+ uses yt5:foobar;
+ leaf-list foo4 { type foobar; }
+ }
+ }
+
+ typedef foo {
+ type int32 {
+ range "-42 | -2 .. +7 | 8 | 41 | 42";
+ }
+ }
+
+ list foo3 {
+ uses foo;
+ key "foo baz bar";
+ uses bar {
+/*
+ extend zzz {
+ container con_zzz {
+ presence "enables foo3_zzz service";
+ }
+ }
+*/
+ }
+
+ unique "goo zzz/zzzz";
+ }
+
+ rpc rpc-one {
+ input {
+ leaf x {type int8; }
+ uses foo;
+ }
+ output { uses bar; }
+ }
+
+ rpc rpc-two;
+
+ rpc rpc-three {
+ input {
+ leaf a { type foo; }
+ container xx;
+ }
+ }
+
+ augment /rpc-two/input {
+ leaf aa { type uint32; }
+ }
+
+ augment /rpc-three/input/xx {
+ leaf aa { type uint32; }
+ }
+
+ notification notif-one;
+
+ notification notif-two {
+ leaf one { type string; }
+ anyxml two;
+ }
+
+ notification notif-three {
+ uses foo;
+ }
+
+}
+
diff --git a/test/lux/yin/test_good/yt6.yang b/test/lux/yin/test_good/yt6.yang
new file mode 100644
index 0000000..e327001
--- /dev/null
+++ b/test/lux/yin/test_good/yt6.yang
@@ -0,0 +1,129 @@
+module yt6 {
+
+ namespace "urn:ietf:params:xml:ns:yang:yt6";
+ prefix "yt6";
+
+ import ietf-yang-types { prefix y; }
+
+ organization
+ "YANG Language Design Team";
+
+ contact
+ "Andy Bierman";
+
+ description
+ "YANG test module 6. Container, augment";
+
+
+ typedef un-1 {
+ type union { // 16
+ type union { // 17
+ type int32;
+ type binary;
+ type union { // 20
+ type string;
+ type binary;
+ type boolean;
+ }
+ }
+ type int64;
+ }
+ default 9;
+ }
+
+ augment /foo/a/z {
+ leaf xxx { type binary; }
+ }
+
+ augment /foo/a {
+ case zz { leaf zzz { type int64; } }
+ }
+
+
+ container foo {
+ leaf un {
+ type un-1;
+ config false;
+ default forty;
+ }
+ leaf bar1 {
+ type y:counter32;
+ }
+ leaf bar2 {
+ type int32;
+ default 10;
+ }
+ leaf bar3 {
+ type int32;
+ mandatory true;
+ }
+ leaf bar4 {
+ type int32;
+ mandatory false;
+ }
+ leaf bar5 {
+ type int32;
+ mandatory true;
+ // default 10; pyang says this is illegal
+ }
+ leaf bar6 {
+ type int32;
+ mandatory false;
+ default 10;
+ }
+ choice a {
+ default x;
+ leaf x { type int32; }
+ leaf y { type string; }
+ container z;
+ }
+ }
+
+ list bar {
+ config false;
+ key bar1;
+ unique zz2;
+ leaf zz1 { type un-1; mandatory true; }
+ leaf zz2 { type y:zero-based-counter32; }
+ leaf-list zz3 {
+ description testing-one-two-three;
+ min-elements 4;
+ max-elements 14;
+ type y:date-and-time;
+ ordered-by user;
+ }
+ leaf bar1 { type un-1; }
+ }
+
+ notification notif1 {
+ description "notification test";
+ reference test-notif-1;
+ status deprecated;
+ container x {
+ list y {
+ reference "RFC 4741";
+ leaf xx { type int32; }
+ leaf zz { type zz_type; }
+
+ key xx;
+
+ max-elements "77";
+ min-elements "15";
+ }
+
+ leaf yy { type int32; default -123; }
+
+ typedef zz_type {
+ type enumeration {
+ enum x;
+ enum y;
+ }
+ }
+ }
+ leaf x2 { type instance-identifier; }
+ anyxml x3 { description test-any; }
+ }
+
+ notification notif2;
+
+}
diff --git a/test/lux/yin/test_good/yt7.yang b/test/lux/yin/test_good/yt7.yang
new file mode 100644
index 0000000..5eabbca
--- /dev/null
+++ b/test/lux/yin/test_good/yt7.yang
@@ -0,0 +1,44 @@
+module yt7 {
+
+ namespace "urn:ietf:params:xml:ns:yang:yt7";
+ prefix "yt7";
+
+ import ietf-yang-types { prefix y; }
+
+ organization
+ "YANG Language Design Team";
+
+ contact
+ "ietf@andybierman.com";
+
+ description
+ "YANG test module 7.";
+
+ revision 2008-02-08 {
+ description "initial version.";
+ }
+
+ rpc rpc1 {
+ description rpc-test;
+ reference "RFC 4741";
+ input {
+ leaf a { type y:counter32; }
+ leaf b { type int32; }
+ container foo {
+ presence "enable foo service";
+ }
+ }
+ output {
+ leaf x { type y:zero-based-counter32; }
+ container y {
+ container yy {
+ leaf yyy { type empty; }
+ anyxml zzz;
+ container zz;
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/test/lux/yin/test_good/yt8.yang b/test/lux/yin/test_good/yt8.yang
new file mode 100644
index 0000000..e5b6bbf
--- /dev/null
+++ b/test/lux/yin/test_good/yt8.yang
@@ -0,0 +1,27 @@
+module yt8 {
+
+ namespace "urn:ietf:params:xml:ns:yang:yt8";
+ prefix "yt8";
+
+ organization
+ "YANG Language Design Team";
+
+ contact
+ "ietf@andybierman.com";
+
+ description
+ "YANG test module 8.";
+
+ revision 2008-02-12 {
+ description "Initial revision.";
+ }
+
+ typedef foo {
+ type int32 {
+ range "-42 | -2 .. +7 | 8 | 41 | 42" {
+ }
+ }
+ }
+
+}
+
diff --git a/test/lux/yin/test_good/yt9.yang b/test/lux/yin/test_good/yt9.yang
new file mode 100644
index 0000000..889ab87
--- /dev/null
+++ b/test/lux/yin/test_good/yt9.yang
@@ -0,0 +1,20 @@
+module yt9 {
+
+ namespace "urn:ietf:params:xml:ns:yang:yt9";
+
+ prefix "yt9";
+
+ organization "Netconf Central";
+
+ contact "Andy Bierman";
+
+ description "YANG test module 9. augment";
+
+ revision 2008-04-11 { description "initial version"; }
+
+ leaf a1 { type int32; }
+
+ container con1 {
+ leaf a2 { type string; }
+ }
+}
diff --git a/test/lux/yin/yin_plugin_macro.lux b/test/lux/yin/yin_plugin_macro.lux
new file mode 100644
index 0000000..cb98532
--- /dev/null
+++ b/test/lux/yin/yin_plugin_macro.lux
@@ -0,0 +1,57 @@
+# author: lbevemyr@cisco.com
+[doc Test of the yanger yin plugin. Comparing it to the predecessor pyang yin.]
+
+[macro yin_compare FILE]
+ ~yanger -f yin -p ${DIR} ${DIR}/${FILE}
+ ! | sed 's/ *$//' > test.yanger.yin
+ !echo ==$?==
+ ?==0==
+
+ ~pyang --ignore-errors -f yin -p ${DIR} ${DIR}/${FILE}
+ ! | sed 's/ *$//' > test.pyang.yin
+ !echo ==$?==
+ ?==0==
+
+ !diff -u test.pyang.yin test.yanger.yin
+ !echo ==$?==
+ ?==0==
+ -
+[endmacro]
+
+
+[shell test_yanger_yin]
+ [timeout 20]
+
+ [global DIR=../tree]
+ [invoke yin_compare small2.yang]
+ [invoke yin_compare small3.yang]
+ [invoke yin_compare small4.yang]
+ [invoke yin_compare small5.yang]
+ [invoke yin_compare a.yang]
+
+ # use pyang test modules
+ [global DIR=./test_good]
+ [invoke yin_compare yt5.yang]
+ [invoke yin_compare yt6.yang]
+ [invoke yin_compare yt7.yang]
+ [invoke yin_compare yt8.yang]
+ [invoke yin_compare yt9.yang]
+ [invoke yin_compare yt10.yang]
+ [invoke yin_compare qs.yang]
+ [invoke yin_compare q.yang]
+ [invoke yin_compare w.yang]
+ [invoke yin_compare xt5.yang]
+ [invoke yin_compare xt6.yang]
+ [invoke yin_compare xt7.yang]
+ [invoke yin_compare xt10.yang]
+ [invoke yin_compare a.yang]
+ [invoke yin_compare b.yang]
+
+ # use some test modules
+ [global DIR=.]
+ [invoke yin_compare small6.yang]
+
+[cleanup]
+ !rm -f test.yanger.yin
+ !rm -f test.pyang.yin
+
diff --git a/test/lux/yin/yin_plugin_macro_cannoical.lux b/test/lux/yin/yin_plugin_macro_cannoical.lux
new file mode 100644
index 0000000..d4dec37
--- /dev/null
+++ b/test/lux/yin/yin_plugin_macro_cannoical.lux
@@ -0,0 +1,805 @@
+# author: lbevemyr@cisco.com
+[doc Test of the yanger yin plugin with canonical option.]
+
+[shell test_yanger_yin]
+ [timeout 20]
+
+ # use some test modules
+ [global DIR=.]
+ !yanger -f yin -p ${DIR} ${DIR}/small6.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ [global DIR=../tree]
+ !yanger -f yin -p ${DIR} ${DIR}/small2.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of variable
+
+
+
+
+
+ Default value for variable
+
+
+
+
+
+ Variable must be supplied by external server
+
+
+
+
+
+
+
+
+
+ Name for dynamic profile
+
+
+
+
+
+
+
+
+ """
+ !yanger -f yin -p ${DIR} ${DIR}/small5.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ # use pyang test modules
+ [global DIR=../yin/test_good]
+ !yanger -f yin -p ${DIR} ${DIR}/yt5.yang --yin-canonical
+ """???
+
+
+
+
+
+ YANG Language Design Team
+
+
+ ietf@andybierman.com
+
+
+ YANG test module 5.
+
+
+
+ Update test cases.
+
+
+
+
+ Initial revision.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RFC 2021
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ duplicate test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/yt6.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+ YANG Language Design Team
+
+
+ Andy Bierman
+
+
+ YANG test module 6. Container, augment
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ testing-one-two-three
+
+
+
+
+
+
+
+
+
+ notification test
+
+
+ test-notif-1
+
+
+
+
+
+
+
+ RFC 4741
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test-any
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/yt7.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+ YANG Language Design Team
+
+
+ ietf@andybierman.com
+
+
+ YANG test module 7.
+
+
+
+ initial version.
+
+
+
+
+ rpc-test
+
+
+ RFC 4741
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/yt8.yang --yin-canonical
+ """???
+
+
+
+
+
+ YANG Language Design Team
+
+
+ ietf@andybierman.com
+
+
+ YANG test module 8.
+
+
+
+ Initial revision.
+
+
+
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/yt9.yang --yin-canonical
+ """???
+
+
+
+
+
+ Netconf Central
+
+
+ Andy Bierman
+
+
+ YANG test module 9. augment
+
+
+
+ initial version
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/yt10.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+ Netconf Central
+
+
+ Andy Bierman
+
+
+ YANG test module 9. augment
+
+
+
+ initial version
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Particular configuration to retrieve.
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/w.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/xt5.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/xt6.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+
+
+
+
+ barbar
+
+
+ """
+
+ !yanger -f yin -p ${DIR} ${DIR}/xt7.yang --yin-canonical
+ """???
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
\ No newline at end of file
diff --git a/test/lux/yin/yin_plugin_macro_pretty_strings.lux b/test/lux/yin/yin_plugin_macro_pretty_strings.lux
new file mode 100644
index 0000000..d44e338
--- /dev/null
+++ b/test/lux/yin/yin_plugin_macro_pretty_strings.lux
@@ -0,0 +1,57 @@
+# author: lbevemyr@cisco.com
+[doc Test of the yanger yin plugin with the pretty strings option.]
+
+[macro yin_compare FILE]
+ ~yanger -f yin -p ${DIR} ${DIR}/${FILE} --yin-pretty-strings
+ ! | sed 's/ *$//' > test.yanger.yin
+ !echo ==$?==
+ ?==0==
+
+ ~pyang --ignore-errors -f yin -p ${DIR} ${DIR}/${FILE} --yin-pretty-strings
+ ! | sed 's/ *$//' > test.pyang.yin
+ !echo ==$?==
+ ?==0==
+
+ !diff -u test.pyang.yin test.yanger.yin
+ !echo ==$?==
+ ?==0==
+ -
+[endmacro]
+
+
+[shell test_yanger_yin]
+ [timeout 20]
+
+ [global DIR=../tree]
+ [invoke yin_compare small2.yang]
+ [invoke yin_compare small3.yang]
+ [invoke yin_compare small4.yang]
+ [invoke yin_compare small5.yang]
+ [invoke yin_compare a.yang]
+
+ # use pyang test modules
+ [global DIR=./test_good]
+ [invoke yin_compare yt5.yang]
+ [invoke yin_compare yt6.yang]
+ [invoke yin_compare yt7.yang]
+ [invoke yin_compare yt8.yang]
+ [invoke yin_compare yt9.yang]
+ [invoke yin_compare yt10.yang]
+ [invoke yin_compare qs.yang]
+ [invoke yin_compare q.yang]
+ [invoke yin_compare w.yang]
+ [invoke yin_compare xt5.yang]
+ [invoke yin_compare xt6.yang]
+ [invoke yin_compare xt7.yang]
+ [invoke yin_compare xt10.yang]
+ [invoke yin_compare a.yang]
+ [invoke yin_compare b.yang]
+
+ # use some test modules
+ [global DIR=.]
+ [invoke yin_compare small6.yang]
+
+[cleanup]
+ !rm -f test.yanger.yin
+ !rm -f test.pyang.yin
+