Age | Commit message (Collapse) | Author |
|
Default values have never worked in extension for PER.
Note that for default values in the root part of SEQUENCE,
giving a value equal to the DEFAULT value, will result in
the same encoding as if asn1_DEFAULT was given. However,
that behavior is not promised by the documentation. The
documentation says that asn1_DEFAULT should be used for
default values. For DEFAULT in extensions, only implement
what the documentation promises and nothing more.
ERIERL-60
|
|
|
|
* Remove out-commented code
* Fix obvious typos and bad grammar
* Adhere to the conventions for when to use "%" and "%%".
|
|
Stop up using asn1ct_gen:emit/1 with a tuple instead of a list.
Also remove the remaining uses of asn1ct_gen:demit/1.
|
|
The debug option no longer serves any useful purpose.
|
|
That will make code slightly easier to read.
|
|
To make it easier to find your way in the generated code,
add a comment about each attribute in the generated code
for SEQUENCE and SET.
|
|
When the 'maps' option is given, the SEQUENCE and SET types are
represented as maps instead of as records. Optional and default values
must be not be given as asn1_NOVALUE or asn1_DEFAULT in a map passed
to the M:encode/2 function; they must be omitted from the
map. Similarly, when decoding missing values will be omitted from the
map.
No .hrl files will be generated when the 'maps' options is used.
That means values in an ASN.1 module must be retrieved by calling the
appropriate function in generated module.
Since we one day hope to get rid of the options 'compact_bit_string',
'legacy_bit_string', and 'legacy_erlang_types', we will not allow them
to be combined with the 'maps' option.
|
|
|
|
As a preparation for supporting maps in a future commit, refactor
the functions for encoding optional values.
|
|
Most options to the code generation pass are passed through the
process dictionary. At the same time, an Erule or Erules argument
is passed to most code generation functions. The Erule argument
is only an atom indicating the encoding rules ('ber', 'per', or
'uper').
Introduce a new record #gen{} to contain code generation options
and parameters. Pass it as the Erule argument (renaming it to Gen
in functions that we will have to touch anyway). In this commit,
eliminate the use of the variable 'encoding_options' in the process
dictionary.
|
|
|
|
Introduce helper functions to simplify and reduce the size of
gen_encode_constructed_imm/3.
|
|
The to_encoding_order/1 function can be eliminated if we
incorporate its functionality into textual_order/2.
textual_order/2 has a workaround for TermList being longer
than OrderList. Remove the workaround, because the code
being generated would certainly be wrong (better let the compiler
crash and receive a bug report if it happens). The workaround
was not necessary to successfully compile the entire Erlang/OTP
and to run the asn1 test suite.
|
|
As a preparation for future changes, simplify
gen_dec_constructed_imm_2/6 by breaking it apart to two
functions.
|
|
|
|
|
|
NeedRest was introduced in df7bb30f, for unknown reasons (my guess
is that the argument was needed at some point during the development
of the commit).
Found by dialyzer.
|
|
|
|
|
|
|
|
|
|
Instead of generating:
{assign,Dst,"element(2, Val)"}
generate:
{call,erlang,element,[2,{var,"Val"}],Dst}
The latter expression is easier to understand since there is no
need to parse a string which may contain an arbitrary expression.
While at it, also discontinue the practice to treat "naked"
atoms as variables. A variable must always be given as {var,String}.
|
|
To facilitate inlining of apply calls in the intermediate format.
|
|
It will greatly facilitate further optimizations if we include the
intermediate code (if available) in the call_gen tuple.
|
|
For DER/PER/UPER, a value equal to the DEFAULT is not supposed to
be encoded.
BIT STRINGs values can be represented as Erlang terms in four
different ways: as an integer, as a list of zeroes and ones,
as a {Unused,Binary} tuple, or as an Erlang bitstring.
When encoding a BIT STRING, only certain representations of
BIT STRINGs values were recognized. All representations must
be recognized.
When decoding a DEFAULT value for a BIT STRING, the actual value
given in the decoding would be either an integer or a list
of zeroes and one (depending on how the literal was written in
the specification). We expect that the default value should be
in the same representation as any other BIT STRING value (i.e.
by default an Erlang bitstring, or a list if the 'legacy_bitstring'
option has been given, or as compact bitstring if 'compact_bitstring'
has been given).
|
|
|
|
The generated code for table constraints has several problems:
* For each object set, a function for getting an encoding or decoding
fun is generated, regardless of whether it is actually used. In many
specifications, the object set actually used is the union of several
other object sets. That means that the code can become a lot bulkier
than it would need to be.
* The funs are not necessary. The funs just add to the code bloat
and generate more unnecessary garbage at run-time. Also, one of
the arguments of the fun is the name of the field in the class which
is known at compile-time, and the fun for decoding has unused arguments.
How to fix the problems:
At each call site where an open type should be encoded/decoded, call a
specific generated function specialized for the actual object set and
the name of the field in the class. When generating the specialized
functions, make sure that we re-use a previously generated function if
possible.
|
|
There are some minor incompatibilities for BIT STRING:
{bit,Position} is now only only supported for a named
BIT STRING type.
Values longer than the maximum size for the BIT STRING type
would be truncated silently - they now cause an exception.
|
|
As a preparation for rewriting handling of table constraints,
we must make sure that code for decoding a SEQUENCE OF / SET OF
can be be contained in a single clause of a function; thus, we
must not output the helper function for decoding of each component
directly following the code that follows it. Use asn1ct_func:call_gen/3
to delay outputting the helper function.
|
|
|
|
According to the ASN.1 standard, having multiple UNIQUE in class
is allowed. For example:
C ::= CLASS {
&id1 INTEGER UNIQUE,
&id2 INTEGER UNIQUE
}
In practice, no one uses multiple UNIQUE.
The ASN.1 compiler will crash if a class with multiple UNIQUE
is used, but the backends have half-hearted support for multiple
UNIQUE in that they generate helper functions similar to:
getenc_OBJECT_SET(id1, 42) ->
fun enc_XXX/3;
...
Since we have no plans to implement support for multiple UNIQUE
(no one seems to have missed it), simplify the helper functions
like this:
getenc_OBJECT_SET(42) ->
fun enc_XXX/3;
...
|
|
Break out the code to a separate function to make it more readable.
Also avoid hard-coding the name of the value to use as "Val1" as
it may not be true in the future.
Instead of using a list comprenhension like this:
case [X || X <- [element(5, Val),element(6, Val)],
X =/= asn1_NOVALUE] of
[] -> ...;
_ -> ...
end
use an orelse chain:
case element(5, Val) =/= asn1_NOVALUE orelse
element(5, Val) =/= asn1_NOVALUE of
false -> ...;
true -> ...
end
|
|
The first clause of gen_enc_line() allows us to pass in [] as
the value for Element; if we modify the only caller that passes
[] to pass an actual expression we can remove the first clause.
Furthermore, since the Pos argument was only used by the first
clause, we can remove the Pos argument.
We can also remove the first clause in gen_enc_component_optional(),
since the code in its body is exactly the same as in the following
clause.
|
|
An field in a class that references an object or object set is not
allowed to be referenced directly from within a SEQUENCE.
|
|
Using a list comprehension will simplify both the code generator
and the generated code. Also, if there is an ObjFun argument in
the host function, the BEAM compiler will make sure it is only
passed to the generated list comprehension function if it is
actually used.
|
|
When a SEQUENCE was defined inline inside extension addition group
like this:
InlinedSeq ::= SEQUENCE {
...,
[[
s SEQUENCE {
a INTEGER,
b BOOLEAN
}
]]
}
the decoding code would return the contents of the SEQUENCE in a
record named 'InlinedSeq_ExtAddGroup1_s', while the record definition
in the generated HRL file would be 'InlinedSeq_s'.
Since there is no reason to use the longer record name (no risk for
ambiguity), correct the name in the decoding code.
|
|
Simplify the backends by letting asn1ct_check replacing a
with the actual type.
|
|
For the PER backends, generate code for accessing deep table
constraints at compile-time in the same way as is done for BER.
While at it, remove the complicated indentation code.
Also modernize the test suite and add a test for a deeper nested
constraint.
|
|
The name of the referenced object set name in #simpletableattributes{}
would when used by INSTANCE OF be an atom, but in all other cases
be a {Module,ObjectSetName} tuple. Simplify the code by always using
the latter format.
|
|
An ENUMERATED is always represented as a two-tuple, never as
three-tuple.
|
|
asn1ct_constructed_per:gen_encode_prim_wrapper() no longer serves
any useful purpose, as it is easier to call
asn1ct_per:gen_encode_prim() directly. Also, the DoTag argument
for asn1ct_per:gen_encode_prim() is never actually used, so it can
be eliminated at the same time.
|
|
The last clause in asn1ct_gen:type/1 does a catched call to type2/1.
If the type2/1 fails {notype,X} is returned.
Since the body of type2/1 essentially is:
case lists:member(X, [...]) of
true ->
{primitive,bif};
false ->
case lists:member(X, [...]) of
true ->
{constructed,bif};
false ->
{undefined,user}
end
end
there is no way that type2/1 can fail. Therefore, we can eliminate
the catch and put the body of type2/1 into the last clause of
type/1. We can also eliminate the code in the callers of type/1
that match {notype,X}.
|
|
Hiding the details of decoding an external type will facilitate
changing the calling convention in a future commit.
|
|
|
|
The record #typereference{} is only used internally within
the asn1ct_parser2 module (the parser translates it to
an #'Externaltypereference{} record).
|
|
|
|
Improve readability and maintainability.
|
|
Optimize the decoding of CHOICE. Most important is to inline decoding
of the extension bit (if present) and decoding of the choice index
to give the BEAM compiler more opportunities for optimization.
We will also change the structure of the generated code. The current
code uses a flattened case for both the root and extension alternatives:
case Choice + NumRootChoices * Ext of
%% Root alternatives.
0 - ...;
:
LastRootAlternative -> ...;
%% Extension alternatives.
LastRootAlternative+1 -> ...;
:
%% Unknown extension.
_ -> ...;
end
We will instead generate nested cases:
case Ext of
0 ->
case Choice of
%% Root alternatives.
0 - ...;
:
LastRootAlternative -> ...
end;
1 ->
%% Extension alternatives.
<Decode the open type here>
case Choice of
0 -> ...;
:
LastExtensionAlternative -> ...;
%% Unknown extension.
_ -> ...;
end
end
Nested cases should be slightly faster. For decoding of the extensions,
it also makes it possible to hoist the decoding of the open type up
from each case to before the case switching on the extension index,
thus reducing the size of the generated code.
We will also do another change to the structure. Currently, the
big flat clase is wrapped in code that repackages the return values:
{Alt,{Value,RemainingEncodedData}} =
case Choice + NumRootChoices * Ext of
:
end,
{{Value,Alt},RemainingEncodedData}.
We still need to do the repackaging, but we can push it down to
the case arm for decoding each alternative. In many cases, that
will give the BEAM compiler the opportunity to avoid building the
temporary tuples.
|
|
We will need more explicit control of decoding of open types for
CHOICEs, so refactor the gen_dec_line() and gen_dec_line_imm()
to break out the decoding of the open types.
Note that gen_dec_line_special() will not generate correct code
if Ext =/= noext; thus, we can eliminate the Ext parameter.
|