Commit 5c9b2aad authored by Maxime Perrotin's avatar Maxime Perrotin

Add iteration for CHOICE types

parent 7801f5ea
......@@ -11,7 +11,7 @@ install: uninstall
rm -rf obj
@echo Do not forget to export ADA_PROJECT_PATH=$(PREFIX)/share/gpr
test_build: clean install
test_build: install
mkdir -p build_test
cp test/DataView.asn build_test
cd build_test && taste-asn1-iterators -g DataView.asn
......
......@@ -18,7 +18,7 @@ import signal
import argparse
import traceback
import logging
from typing import List
from typing import List, Dict, Tuple
LOG = logging.getLogger(__name__)
......@@ -294,6 +294,109 @@ def sequence_adb_template (sort: str, fields: dict) -> str:
end {sort}_Pkg;'''
def choice_adb_element (options : Dict[str, Tuple[str, str]]) -> List [str]:
''' Code that sets the ASN.1 value of a CHOICE type (Element function) '''
result = []
for field, (EnumID, sort) in options.items():
result.append (f'''when {EnumID} =>
Result.{field} := {sort}_Pkg.To_ASN1 (Container.{field}_val.Element (Container.{field}_it.Position));''')
return result
def choice_adb_image (options : Dict[str, Tuple[str, str]]) -> List [str]:
''' Code for the ASN.1 Value Notation of a CHOICE type '''
result = []
first = True
for field, (EnumID, sort) in options.items():
if not first:
result[-1] += ","
result.append (f'when {EnumID} => {sort}_Pkg.Image (Elm.{field})')
first = False
return result
def choice_adb_iterate (options: Dict[str, Tuple[str, str]]) -> List [str]:
'''
Generate CHOICE iteration code (for the "Next" function)
'''
# Exhaust the last field, then the previous one, and so on
result = []
last_choice = list(options.keys())[-1]
for field, (EnumID, sort) in options.items():
result.append(f'''when {EnumID} =>
Cursor_{field} := Position.{field}_it.Next (Cursor_{field});''')
#if field != last_choice:
result.append(f''' if not P_{field}.Has_Element (Cursor_{field}) then
Cursor_Selector := Position.kind_it.Next (Cursor_Selector);
end if;''')
return result
def choice_adb_template (sort: str, options: Dict[str, Tuple[str, str]]) -> str:
''' Template for iterating on a CHOICE type '''
fields = {name: options[name][1] for name in options.keys()}
selector_pkg = [enum_adb_template (f"{sort}_selection")]
return f'''package body {sort}_Pkg is
-- Implementaiton of the choice selection iterator
{indent(3, selector_pkg)}
procedure Initialize (Container : in out {sort}) is
begin
Container.Kind_it :=
P_Selector.Iterator (Container.Kind_val.Iterate);
{indent(6, fields_adb_init(fields))}
end Initialize;
function Has_Element (Position : Cursor) return Boolean is
(P_Selector.Has_Element (Position.Kind_it.Get_Cursor));
function Iterate (Container : {sort}) return {sort}_It'Class is
begin
return I : {sort}_It do
I.Position := Container'Unrestricted_Access;
end return;
end Iterate;
function First (Item : {sort}_It) return Cursor is
unused_Cursor_kind : P_Selector.Cursor := Item.Position.Kind_it.First;
{indent(6, fields_adb_first(fields))}
begin
return Item.Position;
end First;
function Next (Item : {sort}_It;
Position : Cursor) return Cursor is
pragma Unreferenced (Item);
-- Get the cursor of all the fields to know where we are
Cursor_Selector : P_Selector.Cursor := Position.kind_it.Get_Cursor;
{indent(6, fields_adb_next(fields))}
begin
-- Iterate on the current field then change the kind
case Position.Kind_val.Element(Cursor_Selector) is
{indent(9, choice_adb_iterate(options))}
end case;
return Position;
end Next;
function Image (Elm : asn1Scc{sort}) return String is
begin
return "{{" & {sort}_selection_Pkg.Image (Elm.Kind) & ":"
& (case Elm.Kind is
{indent(18, choice_adb_image(options))})
& "}}";
end Image;
function Element (Container : {sort};
Position : Cursor) return asn1Scc{sort} is
Result : asn1Scc{sort} (Kind => Position.Kind_val.Element (Position.Kind_it.Get_Cursor));
begin
case Result.Kind is
{indent(9, choice_adb_element(options))}
end case;
return Result;
end Element;
end {sort}_Pkg;'''
def top_ads_template(modules: List[str]) -> str:
''' Template for asn1_ada_iterators.ads '''
withs = (f'''with {module}; use {module}; pragma Unreferenced ({module});'''
......@@ -462,6 +565,59 @@ def sequence_ads_template (sort: str, fields: dict) -> str:
end {sort}_Pkg;'''
def choice_ads_template(sort: str, options: dict) -> str:
''' Template for iterating on a CHOICE type '''
selector_pkg = [enum_ads_template (f"{sort}_selection")]
fields = {name: options[name][1] for name in options.keys()}
return f'''package {sort}_Pkg is
-- Create an iterator for the choice selection
{indent(3, selector_pkg)}
package P_Selector renames {sort}_selection_Pkg.It;
{indent(3, fields_ads_pkg(fields))}
type {sort} is new Controlled with record
-- Iterator for the choice selector:
Kind_val : P_Selector.ASN1_Container;
Kind_it : P_Selector.Iterator;
-- And one iterator per choice option:
{indent(6, fields_ads_record(fields))}
end record
with Default_Iterator => Iterate,
Iterator_Element => asn1Scc{sort},
Constant_Indexing => Element;
type Cursor is access all {sort};
-- Constructor (called automatically)
procedure Initialize (Container : in out {sort});
function Has_Element (Position : Cursor) return Boolean;
package Iterators_{sort} is
new Ada.Iterator_Interfaces (Cursor, Has_Element);
type {sort}_It is new Iterators_{sort}.Forward_Iterator with record
Position : Cursor;
end record;
overriding function First (Item : {sort}_It) return Cursor;
overriding function Next (Item : {sort}_It;
Position : Cursor) return Cursor;
function Iterate (Container : {sort}) return {sort}_It'Class;
function Element (Container : {sort};
Position : Cursor) return asn1Scc{sort};
function To_ASN1 (From : asn1Scc{sort})
return asn1Scc{sort} is (From);
subtype Instance is {sort};
function Image (Elm : asn1Scc{sort}) return String;
end {sort}_Pkg;
'''
def init_logging(options):
''' Initialize logging '''
terminal_formatter = logging.Formatter(fmt="[%(levelname)s] %(message)s")
......@@ -575,6 +731,17 @@ def run(options):
child.type.ReferencedTypeName.replace("-", "_")
packages_ads.append(sequence_ads_template(name, fields))
packages_adb.append(sequence_adb_template(name, fields))
elif basic.kind == "ChoiceType":
options = {}
for option, sort in basic.Children.items():
# { fieldName: tuple(EnumID, sortName) }
# with EnumID usually field_PRESENT but not always, depending
# on the renaming policy in case of conflicts with other types
options[option.replace('-', '_')] = \
(sort.EnumID,
sort.type.ReferencedTypeName.replace("-", "_"))
packages_ads.append(choice_ads_template(name, options))
packages_adb.append(choice_adb_template(name, options))
else:
LOG.error("Unsupported type name: " + basic.kind)
return
......
......@@ -31,10 +31,10 @@ MySeq4 ::= SEQUENCE {
b MyVarSeqOf
}
--MyChoice ::= CHOICE {
-- choice-a MyInteger,
-- choice-b MySeqOf
--}
MyChoice ::= CHOICE {
choice-a MyInteger,
choice-b MySeqOf
}
END
......@@ -32,6 +32,7 @@ procedure test_generic is
use MySeqi2_Pkg;
use MySeq3_Pkg;
use MySeq4_Pkg;
use MyChoice_Pkg;
-- Test cases
MyIt : MyInteger_Pkg.Instance;
......@@ -39,11 +40,11 @@ procedure test_generic is
Var_SeqOf : MyVarSeqOf_Pkg.Instance;
Enum : MyEnum_Pkg.Instance;
SeqOfEnum : MySeqOfEnum_Pkg.Instance;
Seq : MySeq_Pkg.Instance;
Seq2 : MySeqi2_Pkg.Instance;
Seq3 : MySeq3_Pkg.Instance;
Seq4 : MySeq4_Pkg.Instance;
Choice : MyChoice_Pkg.Instance;
Seq : MySeq_Pkg.Instance;
Seq2 : MySeqi2_Pkg.Instance;
Seq3 : MySeq3_Pkg.Instance;
Seq4 : MySeq4_Pkg.Instance;
SeqOfItm : asn1SccMySeqOf;
VarSeqOfItm : asn1SccMyVarSeqOf;
......@@ -156,5 +157,21 @@ begin
Put_Line ("total: " & count'img & " values were computed");
New_Line;
Put_Line ("CHOICE with two options");
i := 1;
count := 0;
for each of Choice loop
count := count + 1;
Put (Image (Each) & " ");
i := (if i mod 6 = 0 then 1 else i + 1);
if i = 1 then
New_Line;
end if;
end loop;
New_Line;
Put_Line ("total: " & count'img & " values were computed");
New_Line;
end test_generic;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment