%% vim: tabstop=8:shiftwidth=4 %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2000-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% -module(asn1ct_parser2). -export([parse/1]). -include("asn1_records.hrl"). %% Only used internally within this module. -record(typereference, {pos,val}). %% parse all types in module parse(Tokens) -> case catch parse_ModuleDefinition(Tokens) of {'EXIT',Reason} -> {error,{{undefined,get(asn1_module), [internal,error,'when',parsing,module,definition,Reason]}, hd(Tokens)}}; {asn1_error,Reason} -> {error,{Reason,hd(Tokens)}}; {ModuleDefinition,Rest1} -> {Types,Rest2} = parse_AssignmentList(Rest1), case Rest2 of [{'END',_}|_Rest3] -> {ok,ModuleDefinition#module{typeorval = Types}}; _ -> {error,{{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'END']}, hd(Rest2)}} end end. parse_ModuleDefinition([{typereference,L1,ModuleIdentifier}|Rest0]) -> put(asn1_module,ModuleIdentifier), {_DefinitiveIdentifier,Rest02} = case Rest0 of [{'{',_}|_Rest01] -> parse_ObjectIdentifierValue(Rest0); _ -> {[],Rest0} end, Rest = case Rest02 of [{'DEFINITIONS',_}|Rest03] -> Rest03; _ -> throw({asn1_error,{get_line(hd(Rest02)),get(asn1_module), [got,get_token(hd(Rest02)), expected,'DEFINITIONS']}}) end, {TagDefault,Rest2} = case Rest of [{'EXPLICIT',_L3},{'TAGS',_L4}|Rest1] -> put(tagdefault,'EXPLICIT'), {'EXPLICIT',Rest1}; [{'IMPLICIT',_L3},{'TAGS',_L4}|Rest1] -> put(tagdefault,'IMPLICIT'), {'IMPLICIT',Rest1}; [{'AUTOMATIC',_L3},{'TAGS',_L4}|Rest1] -> put(tagdefault,'AUTOMATIC'), {'AUTOMATIC',Rest1}; Rest1 -> put(tagdefault,'EXPLICIT'), {'EXPLICIT',Rest1} % The default end, {ExtensionDefault,Rest3} = case Rest2 of [{'EXTENSIBILITY',_L5}, {'IMPLIED',_L6}|Rest21] -> put(extensiondefault,'IMPLIED'),{'IMPLIED',Rest21}; _ -> put(extensiondefault,undefined),{undefined,Rest2} end, case Rest3 of [{'::=',_L7}, {'BEGIN',_L8}|Rest4] -> {Exports, Rest5} = parse_Exports(Rest4), {{imports, Imports}, Rest6} = parse_Imports(Rest5), put({get(asn1_module), imports}, Imports), {#module{ pos = L1, name = ModuleIdentifier, defid = [], % fix this tagdefault = TagDefault, extensiondefault = ExtensionDefault, exports = Exports, imports = {imports, Imports}}, Rest6}; _ -> throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module), [got,get_token(hd(Rest3)),expected,"::= BEGIN"]}}) end; parse_ModuleDefinition(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,typereference]}}). parse_Exports([{'EXPORTS',_L1},{';',_L2}|Rest]) -> {{exports,[]},Rest}; parse_Exports([{'EXPORTS',_L1}|Rest]) -> {SymbolList,Rest2} = parse_SymbolList(Rest), case Rest2 of [{';',_}|Rest3] -> {{exports,SymbolList},Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,';']}}) end; parse_Exports(Rest) -> {{exports,all},Rest}. parse_SymbolList(Tokens) -> parse_SymbolList(Tokens,[]). parse_SymbolList(Tokens,Acc) -> {Symbol,Rest} = parse_Symbol(Tokens), case Rest of [{',',_L1}|Rest2] -> parse_SymbolList(Rest2,[Symbol|Acc]); Rest2 -> {lists:reverse([Symbol|Acc]),Rest2} end. parse_Symbol(Tokens) -> parse_Reference(Tokens). parse_Reference([{typereference,L1,TrefName},{'{',_L2},{'}',_L3}|Rest]) -> % {Tref,Rest}; {tref2Exttref(L1,TrefName),Rest}; parse_Reference([Tref1 = {typereference,_,_},{'.',_},Tref2 = {typereference,_,_}, {'{',_L2},{'}',_L3}|Rest]) -> % {{Tref1,Tref2},Rest}; {{tref2Exttref(Tref1),tref2Exttref(Tref2)},Rest}; parse_Reference([Tref = {typereference,_L1,_TrefName}|Rest]) -> {tref2Exttref(Tref),Rest}; parse_Reference([Vref = {identifier,_L1,_VName},{'{',_L2},{'}',_L3}|Rest]) -> {identifier2Extvalueref(Vref),Rest}; parse_Reference([Vref = {identifier,_L1,_VName}|Rest]) -> {identifier2Extvalueref(Vref),Rest}; parse_Reference(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [typereference,identifier]]}}). parse_Imports([{'IMPORTS',_L1},{';',_L2}|Rest]) -> {{imports,[]},Rest}; parse_Imports([{'IMPORTS',_L1}|Rest]) -> {SymbolsFromModuleList,Rest2} = parse_SymbolsFromModuleList(Rest), case Rest2 of [{';',_L2}|Rest3] -> {{imports,SymbolsFromModuleList},Rest3}; Rest3 -> throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module), [got,get_token(hd(Rest3)),expected,';']}}) end; parse_Imports(Tokens) -> {{imports,[]},Tokens}. parse_SymbolsFromModuleList(Tokens) -> parse_SymbolsFromModuleList(Tokens,[]). parse_SymbolsFromModuleList(Tokens,Acc) -> {SymbolsFromModule,Rest} = parse_SymbolsFromModule(Tokens), case (catch parse_SymbolsFromModule(Rest)) of {Sl,_Rest2} when is_record(Sl,'SymbolsFromModule') -> parse_SymbolsFromModuleList(Rest,[SymbolsFromModule|Acc]); _ -> {lists:reverse([SymbolsFromModule|Acc]),Rest} end. parse_SymbolsFromModule(Tokens) -> SetRefModuleName = fun(N) -> fun(X) when is_record(X,'Externaltypereference')-> X#'Externaltypereference'{module=N}; (X) when is_record(X,'Externalvaluereference')-> X#'Externalvaluereference'{module=N} end end, {SymbolList,Rest} = parse_SymbolList(Tokens), case Rest of [{'FROM',_L1},Tref = {typereference,_,Name},Ref={identifier,_L2,_Id},C={',',_}|Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},[Ref,C|Rest2]}; %% This a special case when there is only one Symbol imported %% from the next module. No other way to distinguish Ref from %% a part of the GlobalModuleReference of Name. [{'FROM',_L1},Tref = {typereference,_,Name},Ref = {identifier,_L2,_Id},From = {'FROM',_}|Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},[Ref,From|Rest2]}; [{'FROM',_L1},Tref = {typereference,_,Name},{identifier,_L2,_Id}|Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest2}; [{'FROM',_L1},Tref = {typereference,_,Name},Brace = {'{',_}|Rest2] -> {_ObjIdVal,Rest3} = parse_ObjectIdentifierValue([Brace|Rest2]), % value not used yet, fix me NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest3}; [{'FROM',_L1},Tref = {typereference,_,Name}|Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest2}; _ -> throw({asn1_error,{get_line(hd(Rest)),get(asn1_module), [got,get_token(hd(Rest)),expected, ['FROM typerefernece identifier ,', 'FROM typereference identifier', 'FROM typereference {', 'FROM typereference']]}}) end. parse_ObjectIdentifierValue([{'{',_}|Rest]) -> parse_ObjectIdentifierValue(Rest,[]). parse_ObjectIdentifierValue([{number,_,Num}|Rest],Acc) -> parse_ObjectIdentifierValue(Rest,[Num|Acc]); parse_ObjectIdentifierValue([{identifier,_,Id},{'(',_}, {number,_,Num}, {')',_}|Rest],Acc) -> parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,Num}|Acc]); parse_ObjectIdentifierValue([{identifier,_,Id},{'(',_}, {identifier,_,Id2}, {')',_}|Rest],Acc) -> parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,Id2}|Acc]); parse_ObjectIdentifierValue([{identifier,_,Id},{'(',_}, {typereference,_,Tref},{'.',_},{identifier,_,Id2}, {')',_}|Rest],Acc) -> parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,{'ExternalValue',Tref,Id2}}|Acc]); parse_ObjectIdentifierValue([Id = {identifier,_,_}|Rest],Acc) -> parse_ObjectIdentifierValue(Rest,[identifier2Extvalueref(Id)|Acc]); parse_ObjectIdentifierValue([{'}',_}|Rest],Acc) -> {lists:reverse(Acc),Rest}; parse_ObjectIdentifierValue([H|_T],_Acc) -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected, ['{ some of the following }',number,'identifier ( number )', 'identifier ( identifier )', 'identifier ( typereference.identifier)',identifier]]}}). parse_AssignmentList(Tokens = [{'END',_}|_Rest]) -> {[],Tokens}; parse_AssignmentList(Tokens = [{'$end',_}|_Rest]) -> {[],Tokens}; parse_AssignmentList(Tokens) -> parse_AssignmentList(Tokens,[]). parse_AssignmentList(Tokens= [{'END',_}|_Rest],Acc) -> {lists:reverse(Acc),Tokens}; parse_AssignmentList(Tokens= [{'$end',_}|_Rest],Acc) -> {lists:reverse(Acc),Tokens}; parse_AssignmentList(Tokens,Acc) -> case (catch parse_Assignment(Tokens)) of {'EXIT',Reason} -> exit(Reason); {asn1_error,R} -> % [H|T] = Tokens, throw({error,{R,hd(Tokens)}}); {Assignment,Rest} -> parse_AssignmentList(Rest,[Assignment|Acc]) end. parse_Assignment(Tokens) -> Flist = [fun parse_TypeAssignment/1, fun parse_ValueAssignment/1, fun parse_ObjectClassAssignment/1, fun parse_ObjectAssignment/1, fun parse_ObjectSetAssignment/1, fun parse_ParameterizedAssignment/1, fun parse_ValueSetTypeAssignment/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); {asn1_assignment_error,Reason} -> throw({asn1_error,Reason}); Result -> Result end. parse_or(Tokens,Flist) -> parse_or(Tokens,Flist,[]). parse_or(_Tokens,[],ErrList) -> case ErrList of [] -> throw({asn1_error,{parse_or,ErrList}}); L when is_list(L) -> %% chose to throw 1) the error with the highest line no, %% 2) the last error which is not a asn1_assignment_error or %% 3) the last error. throw(prioritize_error(ErrList)) end; parse_or(Tokens,[Fun|Frest],ErrList) -> case (catch Fun(Tokens)) of Exit = {'EXIT',_Reason} -> parse_or(Tokens,Frest,[Exit|ErrList]); AsnErr = {asn1_error,_} -> parse_or(Tokens,Frest,[AsnErr|ErrList]); AsnAssErr = {asn1_assignment_error,_} -> parse_or(Tokens,Frest,[AsnAssErr|ErrList]); Result = {_,L} when is_list(L) -> Result; Error -> parse_or(Tokens,Frest,[Error|ErrList]) end. parse_or_tag(Tokens,Flist) -> parse_or_tag(Tokens,Flist,[]). parse_or_tag(_Tokens,[],ErrList) -> case ErrList of [] -> throw({asn1_error,{parse_or_tag,ErrList}}); L when is_list(L) -> %% chose to throw 1) the error with the highest line no, %% 2) the last error which is not a asn1_assignment_error or %% 3) the last error. throw(prioritize_error(ErrList)) end; parse_or_tag(Tokens,[{Tag,Fun}|Frest],ErrList) when is_function(Fun) -> case (catch Fun(Tokens)) of Exit = {'EXIT',_Reason} -> parse_or_tag(Tokens,Frest,[Exit|ErrList]); AsnErr = {asn1_error,_} -> parse_or_tag(Tokens,Frest,[AsnErr|ErrList]); AsnAssErr = {asn1_assignment_error,_} -> parse_or_tag(Tokens,Frest,[AsnAssErr|ErrList]); {ParseRes,Rest} when is_list(Rest) -> {{Tag,ParseRes},Rest}; Error -> parse_or_tag(Tokens,Frest,[Error|ErrList]) end. parse_TypeAssignment([{typereference,L1,Tref},{'::=',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#typedef{pos=L1,name=Tref,typespec=Type},Rest2}; parse_TypeAssignment([H1,H2|_Rest]) -> throw({asn1_assignment_error,{get_line(H1),get(asn1_module), [got,[get_token(H1),get_token(H2)], expected, typereference,'::=']}}); parse_TypeAssignment([H|_T]) -> throw({asn1_assignment_error,{get_line(H),get(asn1_module), [got,get_token(H),expected, typereference]}}). %% parse_Type(Tokens) -> Ret %% %% Tokens = [Tok] %% Tok = tuple() %% Ret = #type{} %% parse_Type(Tokens) -> {Tag,Rest3} = case Tokens of [Lbr= {'[',_}|Rest] -> parse_Tag([Lbr|Rest]); Rest-> {[],Rest} end, {Tag2,Rest4} = case Rest3 of [{'IMPLICIT',_}|Rest31] when is_record(Tag,tag)-> {[Tag#tag{type='IMPLICIT'}],Rest31}; [{'EXPLICIT',_}|Rest31] when is_record(Tag,tag)-> {[Tag#tag{type='EXPLICIT'}],Rest31}; Rest31 when is_record(Tag,tag) -> {[Tag#tag{type={default,get(tagdefault)}}],Rest31}; Rest31 -> {Tag,Rest31} end, Flist = [fun parse_BuiltinType/1,fun parse_ReferencedType/1,fun parse_TypeWithConstraint/1], {Type,Rest5} = case (catch parse_or(Rest4,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_Reason} -> throw(AsnErr); Result -> Result end, case hd(Rest5) of {'(',_} -> {Constraints,Rest6} = parse_Constraints(Rest5), if is_record(Type,type) -> {Type#type{constraint=merge_constraints(Constraints), tag=Tag2},Rest6}; true -> {#type{def=Type,constraint=merge_constraints(Constraints), tag=Tag2},Rest6} end; _ -> if is_record(Type,type) -> {Type#type{tag=Tag2},Rest5}; true -> {#type{def=Type,tag=Tag2},Rest5} end end. parse_BuiltinType([{'BIT',_},{'STRING',_}|Rest]) -> case Rest of [{'{',_}|Rest2] -> {NamedNumberList,Rest3} = parse_NamedNumberList(Rest2), case Rest3 of [{'}',_}|Rest4] -> {#type{def={'BIT STRING',NamedNumberList}},Rest4}; _ -> throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module), [got,get_token(hd(Rest3)),expected,'}']}}) end; _ -> {{'BIT STRING',[]},Rest} end; parse_BuiltinType([{'BOOLEAN',_}|Rest]) -> {#type{def='BOOLEAN'},Rest}; %% CharacterStringType ::= RestrictedCharacterStringType | %% UnrestrictedCharacterStringType parse_BuiltinType([{restrictedcharacterstringtype,_,StringName}|Rest]) -> {#type{def=StringName},Rest}; parse_BuiltinType([{'CHARACTER',_},{'STRING',_}|Rest]) -> {#type{def='CHARACTER STRING'},Rest}; parse_BuiltinType([{'CHOICE',_},{'{',_}|Rest]) -> {AlternativeTypeLists,Rest2} = parse_AlternativeTypeLists(Rest), AlternativeTypeLists1 = lists:filter(fun(#'ExtensionAdditionGroup'{}) -> false; ('ExtensionAdditionGroupEnd') -> false; (_) -> true end,AlternativeTypeLists), case Rest2 of [{'}',_}|Rest3] -> AlternativeTypeLists2 = case {[Ext||Ext = #'EXTENSIONMARK'{} <- AlternativeTypeLists1], get(extensiondefault)} of {[],'IMPLIED'} -> AlternativeTypeLists1 ++ [#'EXTENSIONMARK'{}]; _ -> AlternativeTypeLists1 end, {#type{def={'CHOICE',AlternativeTypeLists2}},Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'}']}}) end; parse_BuiltinType([{'EMBEDDED',_},{'PDV',_}|Rest]) -> {#type{def='EMBEDDED PDV'},Rest}; parse_BuiltinType([{'ENUMERATED',_},{'{',_}|Rest]) -> {Enumerations,Rest2} = parse_Enumerations(Rest,get(extensiondefault)), case Rest2 of [{'}',_}|Rest3] -> {#type{def={'ENUMERATED',Enumerations}},Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'}']}}) end; parse_BuiltinType([{'EXTERNAL',_}|Rest]) -> {#type{def='EXTERNAL'},Rest}; % InstanceOfType parse_BuiltinType([{'INSTANCE',_},{'OF',_}|Rest]) -> {DefinedObjectClass,Rest2} = parse_DefinedObjectClass(Rest), case Rest2 of [{'(',_}|_] -> {Constraint,Rest3} = parse_Constraint(Rest2), {#type{def={'INSTANCE OF',DefinedObjectClass,Constraint}},Rest3}; _ -> {#type{def={'INSTANCE OF',DefinedObjectClass,[]}},Rest2} end; % parse_BuiltinType(Tokens) -> parse_BuiltinType([{'INTEGER',_}|Rest]) -> case Rest of [{'{',_}|Rest2] -> {NamedNumberList,Rest3} = parse_NamedNumberList(Rest2), case Rest3 of [{'}',_}|Rest4] -> {#type{def={'INTEGER',NamedNumberList}},Rest4}; _ -> throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module), [got,get_token(hd(Rest3)),expected,'}']}}) end; _ -> {#type{def='INTEGER'},Rest} end; parse_BuiltinType([{'NULL',_}|Rest]) -> {#type{def='NULL'},Rest}; % ObjectClassFieldType fix me later parse_BuiltinType([{'OBJECT',_},{'IDENTIFIER',_}|Rest]) -> {#type{def='OBJECT IDENTIFIER'},Rest}; parse_BuiltinType([{'OCTET',_},{'STRING',_}|Rest]) -> {#type{def='OCTET STRING'},Rest}; parse_BuiltinType([{'REAL',_}|Rest]) -> {#type{def='REAL'},Rest}; parse_BuiltinType([{'RELATIVE-OID',_}|Rest]) -> {#type{def='RELATIVE-OID'},Rest}; parse_BuiltinType([{'SEQUENCE',_},{'{',_},{'}',_}|Rest]) -> {#type{def=#'SEQUENCE'{components=[]}}, Rest}; parse_BuiltinType([{'SEQUENCE',_},{'{',_},{'...',Line},{'}',_}|Rest]) -> {#type{def=#'SEQUENCE'{components=[#'EXTENSIONMARK'{pos = Line}]}},Rest}; parse_BuiltinType([{'SEQUENCE',_},{'{',_},{'...',Line},{'!',_}|Rest]) -> {ExceptionIdentification,Rest2} = parse_ExceptionIdentification(Rest), case Rest2 of [{'}',_}|Rest3] -> {#type{def=#'SEQUENCE'{ components=[#'EXTENSIONMARK'{ pos = Line, val = ExceptionIdentification}]}}, Rest3}; _ -> {ComponentTypeLists,Rest3}= parse_ComponentTypeLists2(Rest2,[#'EXTENSIONMARK'{pos=Line}]), case Rest3 of [{'}',_}|Rest4] -> {#type{def=#'SEQUENCE'{components=ComponentTypeLists}},Rest4}; _ -> throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module), [got,get_token(hd(Rest3)),expected,'}']}}) end % _ -> % Seq case 4,17-19,23-26 will fail here % throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), % [got,get_token(hd(Rest2)),expected,'}']}}) end; parse_BuiltinType([{'SEQUENCE',_},{'{',_}|Rest]) -> {ComponentTypeLists,Rest2} = parse_ComponentTypeLists(Rest), case Rest2 of [{'}',_}|Rest3] -> ComponentTypeLists2 = case {[Ext||Ext = #'EXTENSIONMARK'{} <- ComponentTypeLists], get(extensiondefault)} of {[],'IMPLIED'} -> ComponentTypeLists ++ [#'EXTENSIONMARK'{}]; _ -> ComponentTypeLists end, {#type{def=#'SEQUENCE'{components = ComponentTypeLists2}}, Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'}']}}) end; parse_BuiltinType([{'SEQUENCE',_},{'OF',_},Id={identifier,_,_},Lt={'<',_}|Rest]) -> %% TODO: take care of the identifier for something useful {Type,Rest2} = parse_SelectionType([Id,Lt|Rest]), {#type{def={'SEQUENCE OF',#type{def=Type,tag=[]}}},Rest2}; parse_BuiltinType([{'SEQUENCE',_},{'OF',_},{identifier,_,_} |Rest]) -> %% TODO: take care of the identifier for something useful {Type,Rest2} = parse_Type(Rest), {#type{def={'SEQUENCE OF',Type}},Rest2}; parse_BuiltinType([{'SEQUENCE',_},{'OF',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#type{def={'SEQUENCE OF',Type}},Rest2}; parse_BuiltinType([{'SET',_},{'{',_},{'...',Line},{'}',_}|Rest]) -> {#type{def=#'SET'{components=[#'EXTENSIONMARK'{pos = Line}]}},Rest}; parse_BuiltinType([{'SET',_},{'{',_},{'...',Line},{'!',_}|Rest]) -> {ExceptionIdentification,Rest2} = parse_ExceptionIdentification(Rest), case Rest2 of [{'}',_}|Rest3] -> {#type{def=#'SET'{components= [#'EXTENSIONMARK'{pos = Line, val = ExceptionIdentification}]}}, Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'}']}}) end; parse_BuiltinType([{'SET',_},{'{',_}|Rest]) -> {ComponentTypeLists,Rest2} = parse_ComponentTypeLists(Rest), case Rest2 of [{'}',_}|Rest3] -> ComponentTypeLists2 = case {[Ext||Ext = #'EXTENSIONMARK'{} <- ComponentTypeLists], get(extensiondefault)} of {[],'IMPLIED'} -> ComponentTypeLists ++ [#'EXTENSIONMARK'{}]; _ -> ComponentTypeLists end, {#type{def=#'SET'{components = ComponentTypeLists2}}, Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'}']}}) end; parse_BuiltinType([{'SET',_},{'OF',_},Id={identifier,_,_},Lt={'<',_}|Rest]) -> %% TODO: take care of the identifier for something useful {Type,Rest2} = parse_SelectionType([Id,Lt|Rest]), {#type{def={'SET OF',#type{def=Type,tag=[]}}},Rest2}; parse_BuiltinType([{'SET',_},{'OF',_},{identifier,_,_}|Rest]) -> %%TODO: take care of the identifier for something useful {Type,Rest2} = parse_Type(Rest), {#type{def={'SET OF',Type}},Rest2}; parse_BuiltinType([{'SET',_},{'OF',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#type{def={'SET OF',Type}},Rest2}; %% The so called Useful types parse_BuiltinType([{'GeneralizedTime',_}|Rest]) -> {#type{def='GeneralizedTime'},Rest}; parse_BuiltinType([{'UTCTime',_}|Rest]) -> {#type{def='UTCTime'},Rest}; parse_BuiltinType([{'ObjectDescriptor',_}|Rest]) -> {#type{def='ObjectDescriptor'},Rest}; %% For compatibility with old standard parse_BuiltinType([{'ANY',_},{'DEFINED',_},{'BY',_},{identifier,_,Id}|Rest]) -> {#type{def={'ANY_DEFINED_BY',Id}},Rest}; parse_BuiltinType([{'ANY',_}|Rest]) -> {#type{def='ANY'},Rest}; parse_BuiltinType(Tokens) -> parse_ObjectClassFieldType(Tokens). % throw({asn1_error,unhandled_type}). parse_TypeWithConstraint([{'SEQUENCE',_},Lpar = {'(',_}|Rest]) -> {Constraint,Rest2} = parse_Constraint([Lpar|Rest]), Rest4 = case Rest2 of [{'OF',_}, {identifier,_,_Id}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> throw({asn1_error, {get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'OF']}}) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SEQUENCE OF',Type}, constraint = merge_constraints([Constraint])},Rest5}; parse_TypeWithConstraint([{'SEQUENCE',_},{'SIZE',_},Lpar = {'(',_}|Rest]) -> {Constraint,Rest2} = parse_Constraint([Lpar|Rest]), #constraint{c=C} = Constraint, Constraint2 = Constraint#constraint{c={'SizeConstraint',C}}, Rest4 = case Rest2 of [{'OF',_}, {identifier,_,_Id}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'OF']}}) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SEQUENCE OF',Type}, constraint = merge_constraints([Constraint2])},Rest5}; parse_TypeWithConstraint([{'SET',_},Lpar = {'(',_}|Rest]) -> {Constraint,Rest2} = parse_Constraint([Lpar|Rest]), Rest4 = case Rest2 of [{'OF',_}, {identifier,_,_Id}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> throw({asn1_error, {get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'OF']}}) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SET OF',Type}, constraint = merge_constraints([Constraint])},Rest5}; parse_TypeWithConstraint([{'SET',_},{'SIZE',_},Lpar = {'(',_}|Rest]) -> {Constraint,Rest2} = parse_Constraint([Lpar|Rest]), #constraint{c=C} = Constraint, Constraint2 = Constraint#constraint{c={'SizeConstraint',C}}, Rest4 = case Rest2 of [{'OF',_}, {identifier,_,_Id}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> throw({asn1_error, {get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'OF']}}) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SET OF',Type}, constraint = merge_constraints([Constraint2])},Rest5}; parse_TypeWithConstraint(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, ['SEQUENCE','SEQUENCE SIZE','SET','SET SIZE'], followed,by,a,constraint]}}). %% -------------------------- parse_ReferencedType(Tokens) -> Flist = [fun parse_DefinedType/1, fun parse_SelectionType/1, fun parse_TypeFromObject/1, fun parse_ValueSetFromObjects/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_DefinedType(Tokens=[{typereference,_,_},{'{',_}|_Rest]) -> parse_ParameterizedType(Tokens); parse_DefinedType(Tokens=[{typereference,L1,TypeName}, T2={typereference,_,_},T3={'{',_}|Rest]) -> case (catch parse_ParameterizedType(Tokens)) of {'EXIT',_Reason} -> Rest2 = [T2,T3|Rest], {#type{def = #'Externaltypereference'{pos=L1, module=resolve_module(TypeName), type=TypeName}},Rest2}; {asn1_error,_} -> Rest2 = [T2,T3|Rest], {#type{def = #'Externaltypereference'{pos=L1, module=resolve_module(TypeName), type=TypeName}},Rest2}; Result -> Result end; parse_DefinedType(Tokens=[{typereference,_L1,_Module},{'.',_}, {typereference,_,_TypeName},{'{',_}|_Rest]) -> parse_ParameterizedType(Tokens); parse_DefinedType([{typereference,L1,Module},{'.',_},{typereference,_,TypeName}|Rest]) -> {#type{def = #'Externaltypereference'{pos=L1,module=Module,type=TypeName}},Rest}; parse_DefinedType([{typereference,L1,TypeName}|Rest]) -> case is_pre_defined_class(TypeName) of false -> {#type{def = #'Externaltypereference'{pos=L1,module=resolve_module(TypeName), type=TypeName}},Rest}; _ -> throw({asn1_error, {L1,get(asn1_module), [got,TypeName,expected, [typereference,'typereference.typereference', 'typereference typereference']]}}) end; parse_DefinedType(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [typereference,'typereference.typereference', 'typereference typereference']]}}). parse_SelectionType([{identifier,_,Name},{'<',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {{'SelectionType',Name,Type},Rest2}; parse_SelectionType(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'identifier <']}}). resolve_module(Type) -> Current = get(asn1_module), Imports = get({Current, imports}), resolve_module(Type, Current, Imports). resolve_module(_Type, Current, undefined) -> Current; resolve_module(Type, Current, Imports) -> case [Mod || #'SymbolsFromModule'{symbols = S, module = Mod} <- Imports, #'Externaltypereference'{type = T} <- S, Type == T] of [#'Externaltypereference'{type = Mod}|_] -> Mod; %% This allows the same symbol to be imported several times %% which ought to be checked elsewhere and flagged as an error [] -> Current end. %% -------------------------- %% This should probably be removed very soon % parse_ConstrainedType(Tokens) -> % case (catch parse_TypeWithConstraint(Tokens)) of % {'EXIT',Reason} -> % {Type,Rest} = parse_Type(Tokens), % {Constraint,Rest2} = parse_Constraint(Rest), % {Type#type{constraint=Constraint},Rest2}; % {asn1_error,Reason2} -> % {Type,Rest} = parse_Type(Tokens), % {Constraint,Rest2} = parse_Constraint(Rest), % {Type#type{constraint=Constraint},Rest2}; % Result -> % Result % end. parse_Constraints(Tokens) -> parse_Constraints(Tokens,[]). parse_Constraints(Tokens,Acc) -> {Constraint,Rest} = parse_Constraint(Tokens), case Rest of [{'(',_}|_Rest2] -> parse_Constraints(Rest,[Constraint|Acc]); _ -> {lists:reverse([Constraint|Acc]),Rest} end. parse_Constraint([{'(',_}|Rest]) -> {Constraint,Rest2} = parse_ConstraintSpec(Rest), {Exception,Rest3} = parse_ExceptionSpec(Rest2), case Rest3 of [{')',_}|Rest4] -> {#constraint{c=Constraint,e=Exception},Rest4}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,')']}}) end; parse_Constraint(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'(']}}). parse_ConstraintSpec(Tokens) -> Flist = [fun parse_GeneralConstraint/1, fun parse_SubtypeConstraint/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); {asn1_error,Reason2} -> throw({asn1_error,Reason2}); Result -> Result end. parse_ExceptionSpec([LPar={')',_}|Rest]) -> {undefined,[LPar|Rest]}; parse_ExceptionSpec([{'!',_}|Rest]) -> parse_ExceptionIdentification(Rest); parse_ExceptionSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,[')','!']]}}). parse_ExceptionIdentification(Tokens) -> Flist = [fun parse_SignedNumber/1, fun parse_DefinedValue/1, fun parse_TypeColonValue/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); {asn1_error,Reason2} -> throw({asn1_error,Reason2}); Result -> Result end. parse_TypeColonValue(Tokens) -> {Type,Rest} = parse_Type(Tokens), case Rest of [{':',_}|Rest2] -> {Value,Rest3} = parse_Value(Rest2), {{Type,Value},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,':']}}) end. parse_SubtypeConstraint(Tokens) -> parse_ElementSetSpecs(Tokens). parse_ElementSetSpecs([{'...',_}|Rest]) -> {Elements,Rest2} = parse_ElementSetSpec(Rest), {{[],Elements},Rest2}; parse_ElementSetSpecs(Tokens) -> {RootElems,Rest} = parse_ElementSetSpec(Tokens), case Rest of [{',',_},{'...',_},{',',_}|Rest2] -> {AdditionalElems,Rest3} = parse_ElementSetSpec(Rest2), {{RootElems,AdditionalElems},Rest3}; [{',',_},{'...',_}|Rest2] -> {{RootElems,[]},Rest2}; _ -> {RootElems,Rest} end. parse_ElementSetSpec([{'ALL',_},{'EXCEPT',_}|Rest]) -> {Exclusions,Rest2} = parse_Elements(Rest), {{'ALL',{'EXCEPT',Exclusions}},Rest2}; parse_ElementSetSpec(Tokens) -> parse_Unions(Tokens). %% parse_Unions(Tokens) -> {Ret,Rest} %% Tokens = [Tok] %% Tok = tuple() %% Ret = {'SingleValue',list()} | list() | %% parse_Unions(Tokens) -> {InterSec,Rest} = parse_Intersections(Tokens), {Unions,Rest2} = parse_UnionsRec(Rest), case {InterSec,Unions} of {InterSec,[]} -> {InterSec,Rest2}; {{'SingleValue',V1},{'SingleValue',V2}} -> {{'SingleValue',ordsets:union(to_set(V1),to_set(V2))},Rest2}; {V1,V2} when is_list(V2) -> {[V1] ++ [union|V2],Rest2}; {V1,V2} -> {[V1,union,V2],Rest2} % Other -> % throw(Other) end. parse_UnionsRec([{'|',_}|Rest]) -> {InterSec,Rest2} = parse_Intersections(Rest), {URec,Rest3} = parse_UnionsRec(Rest2), case {InterSec,URec} of {V1,[]} -> {V1,Rest3}; {{'SingleValue',V1},{'SingleValue',V2}} -> {{'SingleValue',ordsets:union(to_set(V1),to_set(V2))},Rest3}; {V1,V2} when is_list(V2) -> {[V1] ++ [union|V2],Rest3}; {V1,V2} -> {[V1,union,V2],Rest3} end; parse_UnionsRec([{'UNION',Info}|Rest]) -> parse_UnionsRec([{'|',Info}|Rest]); parse_UnionsRec(Tokens) -> {[],Tokens}. parse_Intersections(Tokens) -> {InterSec,Rest} = parse_IntersectionElements(Tokens), {IRec,Rest2} = parse_IElemsRec(Rest), case {InterSec,IRec} of {V1,[]} -> {V1,Rest2}; {{'SingleValue',V1},{'SingleValue',V2}} -> {{'SingleValue', ordsets:intersection(to_set(V1),to_set(V2))},Rest2}; {V1,V2} when is_list(V2) -> {[V1] ++ [intersection|V2],Rest2}; {V1,V2} -> {[V1,intersection,V2],Rest2} end. %% parse_IElemsRec(Tokens) -> Result %% Result ::= {'SingleValue',ordered_set()} | list() parse_IElemsRec([{'^',_}|Rest]) -> {InterSec,Rest2} = parse_IntersectionElements(Rest), {IRec,Rest3} = parse_IElemsRec(Rest2), case {InterSec,IRec} of {{'SingleValue',V1},{'SingleValue',V2}} -> {{'SingleValue', ordsets:intersection(to_set(V1),to_set(V2))},Rest3}; {V1,[]} -> {V1,Rest3}; {V1,V2} when is_list(V2) -> {[V1] ++ [intersection|V2],Rest3}; {V1,V2} -> {[V1,intersection,V2],Rest3} end; parse_IElemsRec([{'INTERSECTION',Info}|Rest]) -> parse_IElemsRec([{'^',Info}|Rest]); parse_IElemsRec(Tokens) -> {[],Tokens}. %% parse_IntersectionElements(Tokens) -> {Result,Rest} %% Result ::= InterSec | {InterSec,{'EXCEPT',Exclusion}} %% InterSec ::= {'ALL',{'EXCEPT',Exclusions}} | Unions %% Unions ::= {'SingleValue',list()} | list() (see parse_Unions) %% Exclusions ::= InterSec parse_IntersectionElements(Tokens) -> {InterSec,Rest} = parse_Elements(Tokens), case Rest of [{'EXCEPT',_}|Rest2] -> {Exclusion,Rest3} = parse_Elements(Rest2), {{InterSec,{'EXCEPT',Exclusion}},Rest3}; Rest -> {InterSec,Rest} end. %% parse_Elements(Tokens) -> {Result,Rest} %% Result ::= {'ALL',{'EXCEPT',Exclusions}} | Unions %% Exclusions ::= {'ALL',{'EXCEPT',Exclusions}} | Unions %% Unions ::= {'SingleValue',list()} | list() (see parse_Unions) parse_Elements([{'(',_}|Rest]) -> {Elems,Rest2} = parse_ElementSetSpec(Rest), case Rest2 of [{')',_}|Rest3] -> {Elems,Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,')']}}) end; parse_Elements(Tokens) -> Flist = [fun parse_ObjectSetElements/1, fun parse_SubtypeElements/1, % fun parse_Value/1, % fun parse_Type/1, fun parse_Object/1, fun parse_DefinedObjectSet/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); Err = {asn1_error,_} -> throw(Err); Result = {Val,_} when is_record(Val,type) -> Result; Result -> Result end. %% -------------------------- parse_DefinedObjectClass([{typereference,_,_ModName},{'.',_},Tr={typereference,_,_ObjClName}|Rest]) -> %% {{objectclassname,ModName,ObjClName},Rest}; % {{objectclassname,tref2Exttref(Tr)},Rest}; {tref2Exttref(Tr),Rest}; parse_DefinedObjectClass([Tr={typereference,_,_ObjClName}|Rest]) -> % {{objectclassname,tref2Exttref(Tr)},Rest}; {tref2Exttref(Tr),Rest}; parse_DefinedObjectClass([{'TYPE-IDENTIFIER',_}|Rest]) -> {'TYPE-IDENTIFIER',Rest}; parse_DefinedObjectClass([{'ABSTRACT-SYNTAX',_}|Rest]) -> {'ABSTRACT-SYNTAX',Rest}; parse_DefinedObjectClass(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, ['typereference . typereference', typereference, 'TYPE-IDENTIFIER', 'ABSTRACT-SYNTAX']]}}). parse_ObjectClassAssignment([{typereference,L1,ObjClName},{'::=',_}|Rest]) -> {Type,Rest2} = parse_ObjectClass(Rest), {#classdef{pos=L1,name=ObjClName,typespec=Type},Rest2}; parse_ObjectClassAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, 'typereference ::=']}}). parse_ObjectClass(Tokens) -> Flist = [fun parse_DefinedObjectClass/1, fun parse_ObjectClassDefn/1, fun parse_ParameterizedObjectClass/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); {asn1_error,Reason2} -> throw({asn1_error,Reason2}); Result -> Result end. parse_ObjectClassDefn([{'CLASS',_},{'{',_}|Rest]) -> {Type,Rest2} = parse_FieldSpec(Rest), {WithSyntaxSpec,Rest3} = parse_WithSyntaxSpec(Rest2), {#objectclass{fields=Type,syntax=WithSyntaxSpec},Rest3}; parse_ObjectClassDefn(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'CLASS {']}}). parse_FieldSpec(Tokens) -> parse_FieldSpec(Tokens,[]). parse_FieldSpec(Tokens,Acc) -> Flist = [fun parse_FixedTypeValueFieldSpec/1, fun parse_VariableTypeValueFieldSpec/1, fun parse_ObjectFieldSpec/1, fun parse_FixedTypeValueSetFieldSpec/1, fun parse_VariableTypeValueSetFieldSpec/1, fun parse_TypeFieldSpec/1, fun parse_ObjectSetFieldSpec/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); {Type,[{'}',_}|Rest]} -> {lists:reverse([Type|Acc]),Rest}; {Type,[{',',_}|Rest2]} -> parse_FieldSpec(Rest2,[Type|Acc]); {_,[H|_T]} -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'}']}}) end. parse_PrimitiveFieldName([{typefieldreference,_,FieldName}|Rest]) -> {{typefieldreference,FieldName},Rest}; parse_PrimitiveFieldName([{valuefieldreference,_,FieldName}|Rest]) -> {{valuefieldreference,FieldName},Rest}; parse_PrimitiveFieldName(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [typefieldreference,valuefieldreference]]}}). parse_FieldName(Tokens) -> {Field,Rest} = parse_PrimitiveFieldName(Tokens), parse_FieldName(Rest,[Field]). parse_FieldName([{'.',_}|Rest],Acc) -> case (catch parse_PrimitiveFieldName(Rest)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); {FieldName,Rest2} -> parse_FieldName(Rest2,[FieldName|Acc]) end; parse_FieldName(Tokens,Acc) -> {lists:reverse(Acc),Tokens}. parse_FixedTypeValueFieldSpec([{valuefieldreference,L1,VFieldName}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {Unique,Rest3} = case Rest2 of [{'UNIQUE',_}|Rest4] -> {'UNIQUE',Rest4}; _ -> {undefined,Rest2} end, {OptionalitySpec,Rest5} = parse_ValueOptionalitySpec(Rest3), case {Unique,Rest5} of {'UNIQUE',[{Del,_}|_]} when Del =:= ','; Del =:= '}' -> case OptionalitySpec of {'DEFAULT',_} -> throw({asn1_error, {L1,get(asn1_module), ['UNIQUE and DEFAULT in same field',VFieldName]}}); _ -> {{fixedtypevaluefield,VFieldName,Type,Unique,OptionalitySpec},Rest5} end; {_,[{Del,_}|_]} when Del =:= ','; Del =:= '}' -> {{object_or_fixedtypevalue_field,VFieldName,Type,Unique,OptionalitySpec},Rest5}; _ -> throw({asn1_error,{L1,get(asn1_module), [got,get_token(hd(Rest5)),expected,[',','}']]}}) end; parse_FixedTypeValueFieldSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,valuefieldreference]}}). parse_VariableTypeValueFieldSpec([{valuefieldreference,L,VFieldName}|Rest]) -> {FieldRef,Rest2} = parse_FieldName(Rest), {OptionalitySpec,Rest3} = parse_ValueOptionalitySpec(Rest2), case Rest3 of [{Del,_}|_] when Del =:= ','; Del =:= '}' -> {{variabletypevaluefield,VFieldName,FieldRef,OptionalitySpec},Rest3}; _ -> throw({asn1_error,{L,get(asn1_module), [got,get_token(hd(Rest3)),expected,[',','}']]}}) end; parse_VariableTypeValueFieldSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,valuefieldreference]}}). parse_ObjectFieldSpec([{valuefieldreference,L,VFieldName}|Rest]) -> {Class,Rest2} = parse_DefinedObjectClass(Rest), {OptionalitySpec,Rest3} = parse_ObjectOptionalitySpec(Rest2), case Rest3 of [{Del,_}|_] when Del =:= ','; Del =:= '}' -> {{objectfield,VFieldName,Class,undefined,OptionalitySpec},Rest3}; _ -> throw({asn1_error,{L,get(asn1_module), [got,get_token(hd(Rest3)),expected,[',','}']]}}) end; parse_ObjectFieldSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,valuefieldreference]}}). parse_TypeFieldSpec([{typefieldreference,L,TFieldName}|Rest]) -> {OptionalitySpec,Rest2} = parse_TypeOptionalitySpec(Rest), case Rest2 of [{Del,_}|_] when Del =:= ','; Del =:= '}' -> {{typefield,TFieldName,OptionalitySpec},Rest2}; _ -> throw({asn1_error,{L,get(asn1_module), [got,get_token(hd(Rest2)),expected,[',','}']]}}) end; parse_TypeFieldSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,typefieldreference]}}). parse_FixedTypeValueSetFieldSpec([{typefieldreference,L,TFieldName}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {OptionalitySpec,Rest3} = parse_ValueSetOptionalitySpec(Rest2), case Rest3 of [{Del,_}|_] when Del =:= ','; Del =:= '}' -> {{objectset_or_fixedtypevalueset_field,TFieldName,Type, OptionalitySpec},Rest3}; _ -> throw({asn1_error,{L,get(asn1_module), [got,get_token(hd(Rest3)),expected,[',','}']]}}) end; parse_FixedTypeValueSetFieldSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,typefieldreference]}}). parse_VariableTypeValueSetFieldSpec([{typefieldreference,L,TFieldName}|Rest]) -> {FieldRef,Rest2} = parse_FieldName(Rest), {OptionalitySpec,Rest3} = parse_ValueSetOptionalitySpec(Rest2), case Rest3 of [{Del,_}|_] when Del =:= ','; Del =:= '}' -> {{variabletypevaluesetfield,TFieldName,FieldRef,OptionalitySpec},Rest3}; _ -> throw({asn1_error,{L,get(asn1_module), [got,get_token(hd(Rest3)),expected,[',','}']]}}) end; parse_VariableTypeValueSetFieldSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,typefieldreference]}}). parse_ObjectSetFieldSpec([{typefieldreference,L,TFieldName}|Rest]) -> {Class,Rest2} = parse_DefinedObjectClass(Rest), {OptionalitySpec,Rest3} = parse_ObjectSetOptionalitySpec(Rest2), case Rest3 of [{Del,_}|_] when Del =:= ','; Del =:= '}' -> {{objectsetfield,TFieldName,Class,OptionalitySpec},Rest3}; _ -> throw({asn1_error,{L,get(asn1_module), [got,get_token(hd(Rest3)),expected,[',','}']]}}) end; parse_ObjectSetFieldSpec(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,typefieldreference]}}). parse_ValueOptionalitySpec(Tokens)-> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {Value,Rest2} = parse_Value(Rest), {{'DEFAULT',Value},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_ObjectOptionalitySpec(Tokens) -> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {Object,Rest2} = parse_Object(Rest), {{'DEFAULT',Object},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_TypeOptionalitySpec(Tokens) -> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {Type,Rest2} = parse_Type(Rest), {{'DEFAULT',Type},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_ValueSetOptionalitySpec(Tokens) -> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {ValueSet,Rest2} = parse_ValueSet(Rest), {{'DEFAULT',ValueSet},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_ObjectSetOptionalitySpec(Tokens) -> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {ObjectSet,Rest2} = parse_ObjectSet(Rest), {{'DEFAULT',ObjectSet},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_WithSyntaxSpec([{'WITH',_},{'SYNTAX',_}|Rest]) -> {SyntaxList,Rest2} = parse_SyntaxList(Rest), {{'WITH SYNTAX',SyntaxList},Rest2}; parse_WithSyntaxSpec(Tokens) -> {[],Tokens}. parse_SyntaxList([{'{',_},{'}',_}|Rest]) -> {[],Rest}; parse_SyntaxList([{'{',_}|Rest]) -> parse_SyntaxList(Rest,[]); parse_SyntaxList(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,['{}','{']]}}). parse_SyntaxList(Tokens,Acc) -> {SyntaxList,Rest} = parse_TokenOrGroupSpec(Tokens), case Rest of [{'}',_}|Rest2] -> {lists:reverse([SyntaxList|Acc]),Rest2}; _ -> parse_SyntaxList(Rest,[SyntaxList|Acc]) end. parse_TokenOrGroupSpec(Tokens) -> Flist = [fun parse_RequiredToken/1, fun parse_OptionalGroup/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_RequiredToken([{typereference,L1,WordName}|Rest]) -> case is_word(WordName) of false -> throw({asn1_error,{L1,get(asn1_module), [got,WordName,expected,a,'Word']}}); true -> {WordName,Rest} end; parse_RequiredToken([{',',L1}|Rest]) -> {{',',L1},Rest}; parse_RequiredToken([{WordName,L1}|Rest]) -> case is_word(WordName) of false -> throw({asn1_error,{L1,get(asn1_module), [got,WordName,expected,a,'Word']}}); true -> {WordName,Rest} end; parse_RequiredToken(Tokens) -> parse_PrimitiveFieldName(Tokens). parse_OptionalGroup([{'[',_}|Rest]) -> {Spec,Rest2} = parse_TokenOrGroupSpec(Rest), {SpecList,Rest3} = parse_OptionalGroup(Rest2,[Spec]), {SpecList,Rest3}. parse_OptionalGroup([{']',_}|Rest],Acc) -> {lists:reverse(Acc),Rest}; parse_OptionalGroup(Tokens,Acc) -> {Spec,Rest} = parse_TokenOrGroupSpec(Tokens), parse_OptionalGroup(Rest,[Spec|Acc]). parse_DefinedObject([Id={identifier,_,_ObjName}|Rest]) -> {{object,identifier2Extvalueref(Id)},Rest}; parse_DefinedObject([{typereference,L1,ModName},{'.',_},{identifier,_,ObjName}|Rest]) -> {{object, #'Externaltypereference'{pos=L1,module=ModName,type=ObjName}},Rest}; parse_DefinedObject(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [identifier,'typereference.identifier']]}}). parse_ObjectAssignment([{identifier,L1,ObjName}|Rest]) -> {Class,Rest2} = parse_DefinedObjectClass(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Object,Rest4} = parse_Object(Rest3), {#typedef{pos=L1,name=ObjName, typespec=#'Object'{classname=Class,def=Object}},Rest4}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}); Other -> throw({asn1_error,{L1,get(asn1_module), [got,Other,expected,'::=']}}) end; parse_ObjectAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,identifier]}}). %% parse_Object(Tokens) -> Ret %% Tokens = [Tok] %% Tok = tuple() %% Ret = {object,_} | {object, _, _} parse_Object(Tokens) -> Flist=[fun parse_ObjectDefn/1, fun parse_ObjectFromObject/1, fun parse_ParameterizedObject/1, fun parse_DefinedObject/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_ObjectDefn(Tokens) -> Flist=[fun parse_DefaultSyntax/1, fun parse_DefinedSyntax/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_DefaultSyntax([{'{',_},{'}',_}|Rest]) -> {{object,defaultsyntax,[]},Rest}; parse_DefaultSyntax([{'{',_}|Rest]) -> parse_DefaultSyntax(Rest,[]); parse_DefaultSyntax(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,['{}','{']]}}). parse_DefaultSyntax(Tokens,Acc) -> {Setting,Rest} = parse_FieldSetting(Tokens), case Rest of [{',',_}|Rest2] -> parse_DefaultSyntax(Rest2,[Setting|Acc]); [{'}',_}|Rest3] -> {{object,defaultsyntax,lists:reverse([Setting|Acc])},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,[',','}']]}}) end. parse_FieldSetting(Tokens) -> {{_,PrimFieldName},Rest} = parse_PrimitiveFieldName(Tokens), {Setting,Rest2} = parse_Setting(Rest), {{PrimFieldName,Setting},Rest2}. parse_DefinedSyntax([{'{',_}|Rest]) -> parse_DefinedSyntax(Rest,[]). parse_DefinedSyntax(Tokens,Acc) -> case Tokens of [{'}',_}|Rest2] -> {{object,definedsyntax,lists:reverse(Acc)},Rest2}; _ -> {DefSynTok,Rest3} = parse_DefinedSyntaxToken(Tokens), parse_DefinedSyntax(Rest3,[DefSynTok|Acc]) end. %% DefinedSyntaxToken ::= Literal | Setting %% Literal ::= word | ',' %% Setting ::= Type | Value | ValueSet | Object | ObjectSet %% word equals typereference, but no lower cases parse_DefinedSyntaxToken([{',',L1}|Rest]) -> {{',',L1},Rest}; %% ObjectClassFieldType or a defined type with a constraint. %% Should also be able to parse a parameterized type. It may be %% impossible to distinguish between a parameterized type and a Literal %% followed by an object set. parse_DefinedSyntaxToken(Tokens=[{typereference,L1,_Name},{T,_}|_Rest]) when T == '.'; T == '(' -> case catch parse_Setting(Tokens) of {asn1_error,_} -> throw({asn1_error,{L1,get(asn1_module), [got,hd(Tokens), expected,['Word',setting]]}}); {'EXIT',Reason} -> exit(Reason); Result -> Result end; parse_DefinedSyntaxToken(Tokens=[TRef={typereference,L1,Name}|Rest]) -> case is_word(Name) of false -> case lookahead_definedsyntax(Rest) of word_or_setting -> {{setting,L1,tref2Exttref(TRef)},Rest}; _ -> parse_Setting(Tokens) end; true -> %% {{word_or_setting,L1,Name},Rest} {{word_or_setting,L1,tref2Exttref(TRef)},Rest} end; parse_DefinedSyntaxToken(Tokens) -> case catch parse_Setting(Tokens) of {asn1_error,_} -> parse_Word(Tokens); {'EXIT',Reason} -> exit(Reason); Result -> Result end. lookahead_definedsyntax([{typereference,_,Name}|_Rest]) -> case is_word(Name) of true -> word_or_setting; _ -> setting end; lookahead_definedsyntax([{'}',_}|_Rest]) -> word_or_setting; lookahead_definedsyntax(_) -> setting. parse_Word([{Name,Pos}|Rest]) -> case is_word(Name) of false -> throw({asn1_error,{Pos,get(asn1_module), [got,Name, expected,a,'Word']}}); true -> {{word_or_setting,Pos,tref2Exttref(Pos,Name)},Rest} end. parse_Setting(Tokens) -> Flist = [{type_tag,fun parse_Type/1}, {value_tag,fun parse_Value/1}, {object_tag,fun parse_Object/1}, {objectset_tag,fun parse_ObjectSet/1}], case (catch parse_or_tag(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result = {{value_tag,_},_} -> Result; {{Tag,Setting},Rest} when is_atom(Tag) -> {Setting,Rest} end. %% parse_Setting(Tokens) -> %% Flist = [fun parse_Type/1, %% fun parse_Value/1, %% fun parse_Object/1, %% fun parse_ObjectSet/1], %% case (catch parse_or(Tokens,Flist)) of %% {'EXIT',Reason} -> %% exit(Reason); %% AsnErr = {asn1_error,_} -> %% throw(AsnErr); %% Result -> %% Result %% end. parse_DefinedObjectSet([{typereference,L1,ModuleName},{'.',_}, {typereference,L2,ObjSetName}|Rest]) -> {{objectset,L1,#'Externaltypereference'{pos=L2,module=ModuleName, type=ObjSetName}},Rest}; parse_DefinedObjectSet([{typereference,L1,ObjSetName}|Rest]) -> {{objectset,L1,#'Externaltypereference'{pos=L1,module=resolve_module(ObjSetName), type=ObjSetName}},Rest}; parse_DefinedObjectSet(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [typereference,'typereference.typereference']]}}). parse_ObjectSetAssignment([{typereference,L1,ObjSetName}|Rest]) -> {Class,Rest2} = parse_DefinedObjectClass(Rest), case Rest2 of [{'::=',_}|Rest3] -> {ObjectSet,Rest4} = parse_ObjectSet(Rest3), {#typedef{pos=L1,name=ObjSetName, typespec=#'ObjectSet'{class=Class, set=ObjectSet}},Rest4}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}) %%% Other -> %%% throw(Other) end; parse_ObjectSetAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, typereference]}}). %% parse_ObjectSet(Tokens) -> {Ret,Rest} %% Tokens = [Tok] %% Tok = tuple() %% Ret = {[],tuple()} | %% {list(),list()} | %% list() | %% ['EXTENSIONMARK'] | %% {'ALL',{'EXCEPT',Exclusions}} | %% {'SingleValue',SV} %% SV = list() | #'Externalvaluereference'{} | {definedvalue,term()} parse_ObjectSet([{'{',_}|Rest]) -> {ObjSetSpec,Rest2} = parse_ObjectSetSpec(Rest), case Rest2 of [{'}',_}|Rest3] -> {ObjSetSpec,Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'}']}}) end; parse_ObjectSet(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'{']}}). parse_ObjectSetSpec([{'...',_}|Rest]) -> case Rest of [{',',_}|Rest2] -> {Elements,Rest3}=parse_ElementSetSpecs(Rest2), {{[],Elements},Rest3}; _ -> {['EXTENSIONMARK'],Rest} end; parse_ObjectSetSpec(Tokens) -> parse_ElementSetSpecs(Tokens). % moved fun parse_Object/1 and fun parse_DefinedObjectSet/1 to parse_Elements %% parse_ObjectSetElements(Tokens) -> {Result,Rest} %% Result ::= {'ObjectSetFromObjects',Objects,Name} | {pos,ObjectSet,Params} %% Objects ::= ReferencedObjects %% ReferencedObjects ::= (see parse_ReferencedObjects/1) %% Name ::= [FieldName] %% FieldName ::= {typefieldreference,atom()} | {valuefieldreference,atom()} %% ObjectSet ::= {objectset,integer(),#'Externaltypereference'{}} %% Params ::= list() (see parse_ActualParameterList/1) parse_ObjectSetElements(Tokens) -> Flist = [%fun parse_Object/1, %fun parse_DefinedObjectSet/1, fun parse_ObjectSetFromObjects/1, fun parse_ParameterizedObjectSet/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_ObjectClassFieldType(Tokens) -> {Class,Rest} = parse_DefinedObjectClass(Tokens), case Rest of [{'.',_}|Rest2] -> {FieldName,Rest3} = parse_FieldName(Rest2), OCFT = #'ObjectClassFieldType'{ classname=Class, class=Class,fieldname=FieldName}, {#type{def=OCFT},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'.']}}) %%% Other -> %%% throw(Other) end. %parse_ObjectClassFieldValue(Tokens) -> % Flist = [fun parse_OpenTypeFieldVal/1, % fun parse_FixedTypeFieldVal/1], % case (catch parse_or(Tokens,Flist)) of % {'EXIT',Reason} -> % throw(Reason); % AsnErr = {asn1_error,_} -> % throw(AsnErr); % Result -> % Result % end. parse_ObjectClassFieldValue(Tokens) -> parse_OpenTypeFieldVal(Tokens). parse_OpenTypeFieldVal(Tokens) -> {Type,Rest} = parse_Type(Tokens), case Rest of [{':',_}|Rest2] -> {Value,Rest3} = parse_Value(Rest2), {{opentypefieldvalue,Type,Value},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,':']}}) end. % parse_FixedTypeFieldVal(Tokens) -> % parse_Value(Tokens). % parse_InformationFromObjects(Tokens) -> % Flist = [fun parse_ValueFromObject/1, % fun parse_ValueSetFromObjects/1, % fun parse_TypeFromObject/1, % fun parse_ObjectFromObject/1], % case (catch parse_or(Tokens,Flist)) of % {'EXIT',Reason} -> % throw(Reason); % AsnErr = {asn1_error,_} -> % throw(AsnErr); % Result -> % Result % end. %% parse_ReferencedObjects(Tokens) -> {Result,Rest} %% Result ::= DefObject | DefObjSet | %% {po,DefObject,Params} | {pos,DefObjSet,Params} | %% %% DefObject ::= {object,#'Externaltypereference'{}} | %% {object,#'Externalvaluereference'{}} %% DefObjSet ::= {objectset,integer(),#'Externaltypereference'{}} %% Params ::= list() parse_ReferencedObjects(Tokens) -> Flist = [fun parse_DefinedObject/1, fun parse_DefinedObjectSet/1, fun parse_ParameterizedObject/1, fun parse_ParameterizedObjectSet/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_ValueFromObject(Tokens) -> {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), case lists:last(Name) of {valuefieldreference,_} -> {{'ValueFromObject',Objects,Name},Rest3}; _ -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,typefieldreference,expected, valuefieldreference]}}) end; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'.']}}) %%% Other -> %%% throw({asn1_error,{got,Other,expected,'.'}}) end. parse_ValueSetFromObjects(Tokens) -> {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), case lists:last(Name) of {typefieldreference,_FieldName} -> {{'ValueSetFromObjects',Objects,Name},Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected, typefieldreference]}}) end; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'.']}}) %%% Other -> %%% throw({asn1_error,{got,Other,expected,'.'}}) end. parse_TypeFromObject(Tokens) -> {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), case lists:last(Name) of {typefieldreference,_FieldName} -> {{'TypeFromObject',Objects,Name},Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected, typefieldreference]}}) end; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'.']}}) %%% Other -> %%% throw({asn1_error,{got,Other,expected,'.'}}) end. parse_ObjectFromObject(Tokens) -> {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), {{'ObjectFromObject',Objects,Name},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'.']}}) end. %% parse_ObjectSetFromObjects(Tokens) -> {Result,Rest} %% Result ::= {'ObjectSetFromObjects',Objects,Name} %% Objects ::= ReferencedObject (see parse_ReferencedObjects/1) %% Name ::= [FieldName] %% FieldName ::= {typefieldreference,atom()} | %% {valuefieldreference,atom()} parse_ObjectSetFromObjects(Tokens) -> {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), case lists:last(Name) of {typefieldreference,_FieldName} -> {{'ObjectSetFromObjects',Objects,Name},Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected, typefieldreference]}}) end; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'.']}}) end. % parse_InstanceOfType([{'INSTANCE',_},{'OF',_}|Rest]) -> % {Class,Rest2} = parse_DefinedObjectClass(Rest), % {{'InstanceOfType',Class},Rest2}. % parse_InstanceOfValue(Tokens) -> % parse_Value(Tokens). %% X.682 constraint specification parse_GeneralConstraint(Tokens) -> Flist = [fun parse_UserDefinedConstraint/1, fun parse_TableConstraint/1, fun parse_ContentsConstraint/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_UserDefinedConstraint([{'CONSTRAINED',_},{'BY',_},{'{',_},{'}',_}|Rest])-> {{constrained_by,[]},Rest}; parse_UserDefinedConstraint([{'CONSTRAINED',_}, {'BY',_}, {'{',_}|Rest]) -> {Param,Rest2} = parse_UserDefinedConstraintParameter(Rest), case Rest2 of [{'}',_}|Rest3] -> {{constrained_by,Param},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'}']}}) end; parse_UserDefinedConstraint(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, ['CONSTRAINED BY {}','CONSTRAINED BY {']]}}). parse_UserDefinedConstraintParameter(Tokens) -> parse_UserDefinedConstraintParameter(Tokens,[]). parse_UserDefinedConstraintParameter(Tokens,Acc) -> Flist = [fun parse_GovernorAndActualParameter/1, fun parse_ActualParameter/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); {Result,Rest} -> case Rest of [{',',_}|_Rest2] -> parse_UserDefinedConstraintParameter(Tokens,[Result|Acc]); _ -> {lists:reverse([Result|Acc]),Rest} end end. parse_GovernorAndActualParameter(Tokens) -> {Governor,Rest} = parse_Governor(Tokens), case Rest of [{':',_}|Rest2] -> {Params,Rest3} = parse_ActualParameter(Rest2), {{'Governor_Params',Governor,Params},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,':']}}) end. parse_TableConstraint(Tokens) -> Flist = [fun parse_ComponentRelationConstraint/1, fun parse_SimpleTableConstraint/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_SimpleTableConstraint(Tokens) -> {ObjectSet,Rest} = parse_ObjectSet(Tokens), {{simpletable,ObjectSet},Rest}. parse_ComponentRelationConstraint([{'{',_}|Rest]) -> {ObjectSet,Rest2} = parse_DefinedObjectSet(Rest), case Rest2 of [{'}',_},{'{',_}|Rest3] -> {AtNot,Rest4} = parse_AtNotationList(Rest3,[]), case Rest4 of [{'}',_}|Rest5] -> {{componentrelation,ObjectSet,AtNot},Rest5}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'}']}}) end; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected, 'ComponentRelationConstraint',ended,with,'}']}}) %%% Other -> %%% throw(Other) end; parse_ComponentRelationConstraint(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'{']}}). parse_AtNotationList(Tokens,Acc) -> {AtNot,Rest} = parse_AtNotation(Tokens), case Rest of [{',',_}|Rest2] -> parse_AtNotationList(Rest2,[AtNot|Acc]); _ -> {lists:reverse([AtNot|Acc]),Rest} end. parse_AtNotation([{'@',_},{'.',_}|Rest]) -> {CIdList,Rest2} = parse_ComponentIdList(Rest), {{innermost,CIdList},Rest2}; parse_AtNotation([{'@',_}|Rest]) -> {CIdList,Rest2} = parse_ComponentIdList(Rest), {{outermost,CIdList},Rest2}; parse_AtNotation(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,['@','@.']]}}). parse_ComponentIdList(Tokens) -> parse_ComponentIdList(Tokens,[]). parse_ComponentIdList([Id = {identifier,_,_},{'.',_}|Rest],Acc) -> parse_ComponentIdList(Rest,[identifier2Extvalueref(Id)|Acc]); parse_ComponentIdList([Id = {identifier,_,_}|Rest],Acc) -> {lists:reverse([identifier2Extvalueref(Id)|Acc]),Rest}; parse_ComponentIdList(Tokens,_) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [identifier,'identifier.']]}}). parse_ContentsConstraint([{'CONTAINING',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), case Rest2 of [{'ENCODED',_},{'BY',_}|Rest3] -> {Value,Rest4} = parse_Value(Rest3), {{contentsconstraint,Type,Value},Rest4}; _ -> {{contentsconstraint,Type,[]},Rest2} end; parse_ContentsConstraint([{'ENCODED',_},{'BY',_}|Rest]) -> {Value,Rest2} = parse_Value(Rest), {{contentsconstraint,[],Value},Rest2}; parse_ContentsConstraint(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, 'CONTAINING','or','ENCODED BY']}}). % X.683 Parameterization of ASN.1 specifications parse_Governor(Tokens) -> Flist = [fun parse_Type/1, fun parse_DefinedObjectClass/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_ActualParameter(Tokens) -> Flist = [fun parse_Type/1, fun parse_Value/1, fun parse_ValueSet/1, fun parse_DefinedObjectClass/1, fun parse_Object/1, fun parse_ObjectSet/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_ParameterizedAssignment(Tokens) -> Flist = [fun parse_ParameterizedTypeAssignment/1, fun parse_ParameterizedValueAssignment/1, fun parse_ParameterizedValueSetTypeAssignment/1, fun parse_ParameterizedObjectClassAssignment/1, fun parse_ParameterizedObjectAssignment/1, fun parse_ParameterizedObjectSetAssignment/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); AsnAssErr = {asn1_assignment_error,_} -> throw(AsnAssErr); Result -> Result end. %% parse_ParameterizedTypeAssignment(Tokens) -> Result %% Result = {#ptypedef{},Rest} | throw() parse_ParameterizedTypeAssignment([{typereference,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Type,Rest4} = parse_Type(Rest3), {#ptypedef{pos=L1,name=Name,args=ParameterList,typespec=Type}, Rest4}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}) end; parse_ParameterizedTypeAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, typereference]}}). %% parse_ParameterizedValueAssignment(Tokens) -> Result %% Result = {#pvaluedef{},Rest} | throw() parse_ParameterizedValueAssignment([{identifier,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), {Type,Rest3} = parse_Type(Rest2), case Rest3 of [{'::=',_}|Rest4] -> {Value,Rest5} = parse_Value(Rest4), {#pvaluedef{pos=L1,name=Name,args=ParameterList,type=Type, value=Value},Rest5}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}) end; parse_ParameterizedValueAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,identifier]}}). %% parse_ParameterizedValueSetTypeAssignment(Tokens) -> Result %% Result = {#pvaluesetdef{},Rest} | throw() parse_ParameterizedValueSetTypeAssignment([{typereference,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), {Type,Rest3} = parse_Type(Rest2), case Rest3 of [{'::=',_}|Rest4] -> {ValueSet,Rest5} = parse_ValueSet(Rest4), {#pvaluesetdef{pos=L1,name=Name,args=ParameterList, type=Type,valueset=ValueSet},Rest5}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}) end; parse_ParameterizedValueSetTypeAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, typereference]}}). %% parse_ParameterizedObjectClassAssignment(Tokens) -> Result %% Result = {#ptypedef{},Rest} | throw() parse_ParameterizedObjectClassAssignment([{typereference,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Class,Rest4} = parse_ObjectClass(Rest3), {#ptypedef{pos=L1,name=Name,args=ParameterList,typespec=Class}, Rest4}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}) end; parse_ParameterizedObjectClassAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, typereference]}}). %% parse_ParameterizedObjectAssignment(Tokens) -> Result %% Result = {#pobjectdef{},Rest} | throw() parse_ParameterizedObjectAssignment([{identifier,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), {Class,Rest3} = parse_DefinedObjectClass(Rest2), case Rest3 of [{'::=',_}|Rest4] -> {Object,Rest5} = parse_Object(Rest4), {#pobjectdef{pos=L1,name=Name,args=ParameterList, class=Class,def=Object},Rest5}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}) %%% Other -> %%% throw(Other) end; parse_ParameterizedObjectAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,identifier]}}). %% parse_ParameterizedObjectSetAssignment(Tokens) -> Result %% Result = {#pobjectsetdef{},Rest} | throw{} parse_ParameterizedObjectSetAssignment([{typereference,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), {Class,Rest3} = parse_DefinedObjectClass(Rest2), case Rest3 of [{'::=',_}|Rest4] -> {ObjectSet,Rest5} = parse_ObjectSet(Rest4), {#pobjectsetdef{pos=L1,name=Name,args=ParameterList, class=Class,def=ObjectSet},Rest5}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'::=']}}) %%% Other -> %%% throw(Other) end; parse_ParameterizedObjectSetAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, typereference]}}). %% parse_ParameterList(Tokens) -> Result %% Result = [Parameter] %% Parameter = {Governor,Reference} | Reference %% Governor = Type | DefinedObjectClass %% Type = #type{} %% DefinedObjectClass = #'Externaltypereference'{} | %% 'ABSTRACT-SYNTAX' | 'TYPE-IDENTIFIER' %% Reference = #'Externaltypereference'{} | #'Externalvaluereference'{} parse_ParameterList([{'{',_}|Rest]) -> parse_ParameterList(Rest,[]); parse_ParameterList(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'{']}}). parse_ParameterList(Tokens,Acc) -> {Parameter,Rest} = parse_Parameter(Tokens), case Rest of [{',',_}|Rest2] -> parse_ParameterList(Rest2,[Parameter|Acc]); [{'}',_}|Rest3] -> {lists:reverse([Parameter|Acc]),Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,[',','}']]}}) end. parse_Parameter(Tokens) -> Flist = [fun parse_ParamGovAndRef/1, fun parse_Reference/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_ParamGovAndRef(Tokens) -> {ParamGov,Rest} = parse_ParamGovernor(Tokens), case Rest of [{':',_}|Rest2] -> {Ref,Rest3} = parse_Reference(Rest2), {{ParamGov,Ref},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,':']}}) end. parse_ParamGovernor(Tokens) -> Flist = [fun parse_Governor/1, fun parse_Reference/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. % parse_ParameterizedReference(Tokens) -> % {Ref,Rest} = parse_Reference(Tokens), % case Rest of % [{'{',_},{'}',_}|Rest2] -> % {{ptref,Ref},Rest2}; % _ -> % {{ptref,Ref},Rest} % end. parse_SimpleDefinedType([{typereference,L1,ModuleName},{'.',_}, {typereference,_,TypeName}|Rest]) -> {#'Externaltypereference'{pos=L1,module=ModuleName, type=TypeName},Rest}; parse_SimpleDefinedType([Tref={typereference,_,_}|Rest]) -> % {#'Externaltypereference'{pos=L2,module=get(asn1_module), % type=TypeName},Rest}; {tref2Exttref(Tref),Rest}; parse_SimpleDefinedType(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [typereference,'typereference.typereference']]}}). parse_SimpleDefinedValue([{typereference,L1,ModuleName},{'.',_}, {identifier,_,Value}|Rest]) -> {{simpledefinedvalue,#'Externalvaluereference'{pos=L1,module=ModuleName, value=Value}},Rest}; parse_SimpleDefinedValue([Id={identifier,_,_Value}|Rest]) -> {{simpledefinedvalue,identifier2Extvalueref(Id)},Rest}; parse_SimpleDefinedValue(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, ['typereference.identifier',identifier]]}}). parse_ParameterizedType(Tokens) -> {Type,Rest} = parse_SimpleDefinedType(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {{pt,Type,Params},Rest2}. parse_ParameterizedValue(Tokens) -> {Value,Rest} = parse_SimpleDefinedValue(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {{pv,Value,Params},Rest2}. parse_ParameterizedObjectClass(Tokens) -> {Type,Rest} = parse_DefinedObjectClass(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {{poc,Type,Params},Rest2}. parse_ParameterizedObjectSet(Tokens) -> {ObjectSet,Rest} = parse_DefinedObjectSet(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {{pos,ObjectSet,Params},Rest2}. parse_ParameterizedObject(Tokens) -> {Object,Rest} = parse_DefinedObject(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {{po,Object,Params},Rest2}. parse_ActualParameterList([{'{',_}|Rest]) -> parse_ActualParameterList(Rest,[]); parse_ActualParameterList(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'{']}}). parse_ActualParameterList(Tokens,Acc) -> {Parameter,Rest} = parse_ActualParameter(Tokens), case Rest of [{',',_}|Rest2] -> parse_ActualParameterList(Rest2,[Parameter|Acc]); [{'}',_}|Rest3] -> {lists:reverse([Parameter|Acc]),Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,[',','}']]}}) %%% Other -> %%% throw(Other) end. %------------------------- is_word(Token) -> case not_allowed_word(Token) of true -> false; _ -> if is_atom(Token) -> Item = atom_to_list(Token), is_word(Item); is_list(Token), length(Token) == 1 -> check_one_char_word(Token); is_list(Token) -> [A|Rest] = Token, case check_first(A) of true -> check_rest(Rest); _ -> false end end end. not_allowed_word(Name) -> lists:member(Name,["BIT", "BOOLEAN", "CHARACTER", "CHOICE", "EMBEDDED", "END", "ENUMERATED", "EXTERNAL", "FALSE", "INSTANCE", "INTEGER", "INTERSECTION", "MINUS-INFINITY", "NULL", "OBJECT", "OCTET", "PLUS-INFINITY", "REAL", "SEQUENCE", "SET", "TRUE", "UNION"]). check_one_char_word([A]) when $A =< A, $Z >= A -> true; check_one_char_word([_]) -> false. %% unknown item in SyntaxList check_first(A) when $A =< A, $Z >= A -> true; check_first(_) -> false. %% unknown item in SyntaxList check_rest([R,R|_Rs]) when $- == R -> false; %% two consecutive hyphens are not allowed in a word check_rest([R]) when $- == R -> false; %% word cannot end with hyphen check_rest([R|Rs]) when $A==R; $-==R -> check_rest(Rs); check_rest([]) -> true; check_rest(_) -> false. to_set(V) when is_list(V) -> ordsets:from_list(V); to_set(V) -> ordsets:from_list([V]). parse_AlternativeTypeLists(Tokens) -> parse_AlternativeTypeLists(Tokens,[]). parse_AlternativeTypeLists(Tokens = [{identifier,_,_}|_Rest0],Clist) -> {CompList,Rest1} = parse_AlternativeTypeList(Tokens,[]), parse_AlternativeTypeLists(Rest1,Clist++CompList); parse_AlternativeTypeLists([{'...',L1},{'!',_}|Rest02],Clist0) -> {_,Rest03} = parse_ExceptionIdentification(Rest02), %% Exception info is currently thrown away parse_AlternativeTypeLists2(Rest03,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_AlternativeTypeLists([{',',L1},{'...',_},{'!',_}|Rest02],Clist0) when Clist0 =/= []-> {_,Rest03} = parse_ExceptionIdentification(Rest02), %% Exception info is currently thrown away parse_AlternativeTypeLists2(Rest03,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_AlternativeTypeLists([{',',_},{'...',L1}|Rest02],Clist0) when Clist0 =/= []-> parse_AlternativeTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_AlternativeTypeLists([{'...',L1}|Rest02],Clist0) -> parse_AlternativeTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_AlternativeTypeLists(Tokens = [{'}',_L1}|_Rest02],Clist0) -> {Clist0,Tokens}. parse_AlternativeTypeLists2(Tokens,Clist) -> {ExtAdd,Rest} = parse_ExtensionAdditionAlternatives(Tokens,Clist), {Clist2,Rest2} = parse_OptionalExtensionMarker(Rest,lists:flatten(ExtAdd)), case Rest2 of [{',',_}|Rest3] -> {CompList,Rest4} = parse_AlternativeTypeList(Rest3,[]), {Clist2 ++ CompList,Rest4}; _ -> {Clist2,Rest2} end. parse_AlternativeTypeList([{',',_},Id = {identifier,_,_}|Rest],Acc) when Acc =/= [] -> {AlternativeType,Rest2} = parse_NamedType([Id|Rest]), parse_AlternativeTypeList(Rest2,[AlternativeType|Acc]); parse_AlternativeTypeList(Tokens = [{'}',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_AlternativeTypeList(Tokens = [{']',_},{']',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_AlternativeTypeList(Tokens = [{',',_},{'...',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_AlternativeTypeList(Tokens,[]) -> {AlternativeType,Rest} = parse_NamedType(Tokens), parse_AlternativeTypeList(Rest,[AlternativeType]); parse_AlternativeTypeList(Tokens,_) -> throw({asn1_error, {get_line(hd(Tokens)),get(asn1_module), [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))], expected,['}',', identifier']]}}). parse_ExtensionAdditionAlternatives(Tokens =[{',',_}|_],Clist) -> {ExtAddList,Rest2} = parse_ExtensionAdditionAlternativesList(Tokens,[]), {Clist++lists:flatten(ExtAddList),Rest2}; parse_ExtensionAdditionAlternatives(Tokens,Clist) -> %% Empty {Clist,Tokens}. parse_ExtensionAdditionAlternativesList([{',',_},Id = {identifier,_,_}|Rest],Acc) -> {AlternativeType,Rest2} = parse_NamedType([Id|Rest]), parse_ExtensionAdditionAlternativesList(Rest2,[AlternativeType|Acc]); parse_ExtensionAdditionAlternativesList([{',',_},C1 = {'[',_},C2 = {'[',_}|Rest],Acc) -> {ExtAddGroup,Rest2} = parse_ExtensionAdditionAlternativesGroup([C1,C2|Rest],[]), parse_ExtensionAdditionAlternativesList(Rest2,[ExtAddGroup|Acc]); parse_ExtensionAdditionAlternativesList(Tokens = [{'}',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ExtensionAdditionAlternativesList(Tokens = [{',',_},{'...',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ExtensionAdditionAlternativesList(Tokens,_) -> throw({asn1_error, {get_line(hd(Tokens)),get(asn1_module), [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))], expected,['}',', identifier']]}}). parse_ExtensionAdditionAlternativesGroup([ {'[',_},{'[',_},_VsnNr = {number,_,Num},{':',_}|Rest],[]) -> parse_ExtensionAdditionAlternativesGroup2(Rest,Num); parse_ExtensionAdditionAlternativesGroup([ {'[',_},{'[',_}|Rest],[]) -> parse_ExtensionAdditionAlternativesGroup2(Rest,undefined); parse_ExtensionAdditionAlternativesGroup(Tokens,_) -> throw({asn1_error, {get_line(hd(Tokens)),get(asn1_module), [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))], expected,['[[']]}}). parse_ExtensionAdditionAlternativesGroup2(Tokens,Num) -> {CompTypeList,Rest} = parse_AlternativeTypeList(Tokens,[]), case Rest of [{']',_},{']',_}|Rest2] -> {[{'ExtensionAdditionGroup',Num}|CompTypeList] ++ ['ExtensionAdditionGroupEnd'],Rest2}; _ -> throw({asn1_error,{get_line(hd(Rest)),get(asn1_module), [got,get_token(hd(Rest)),expected,[']]']]}}) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% parse_AlternativeTypeLists(Tokens,ExtensionDefault) -> %% {AltTypeList,Rest1} = parse_AlternativeTypeList(Tokens), %% {ExtensionAndException,Rest2} = %% case Rest1 of %% [{',',_},{'...',L1},{'!',_}|Rest12] -> %% {_,Rest13} = parse_ExceptionIdentification(Rest12), %% %% Exception info is currently thrown away %% {[#'EXTENSIONMARK'{pos=L1}],Rest13}; %% [{',',_},{'...',L1}|Rest12] -> %% {[#'EXTENSIONMARK'{pos=L1}],Rest12}; %% _ -> %% {[],Rest1} %% end, %% {AltTypeList2,Rest5} = %% case ExtensionAndException of %% [] -> %% {AltTypeList,Rest2}; %% _ -> %% {ExtensionAddition,Rest3} = %% case Rest2 of %% [{',',_}|Rest23] -> %% parse_ExtensionAdditionAlternativeList(Rest23); %% _ -> %% {[],Rest2} %% end, %% {OptionalExtensionMarker,Rest4} = %% case Rest3 of %% [{',',_},{'...',L3}|Rest31] -> %% {[#'EXTENSIONMARK'{pos=L3}],Rest31}; %% _ -> %% {[],Rest3} %% end, %% {AltTypeList ++ ExtensionAndException ++ %% ExtensionAddition ++ OptionalExtensionMarker, Rest4} %% end, %% AltTypeList3 = %% case [X || X=#'EXTENSIONMARK'{} <- AltTypeList2] of %% [] when ExtensionDefault == 'IMPLIED' -> %% AltTypeList2 ++ [#'EXTENSIONMARK'{}]; %% _ -> %% AltTypeList2 %% end, %% {AltTypeList3,Rest5}. %% parse_AlternativeTypeList(Tokens) -> %% parse_AlternativeTypeList(Tokens,[]). %% parse_AlternativeTypeList(Tokens,Acc) -> %% {NamedType,Rest} = parse_NamedType(Tokens), %% case Rest of %% [{',',_},Id = {identifier,_,_}|Rest2] -> %% parse_AlternativeTypeList([Id|Rest2],[NamedType|Acc]); %% _ -> %% {lists:reverse([NamedType|Acc]),Rest} %% end. %% parse_ExtensionAdditionAlternativeList(Tokens) -> %% parse_ExtensionAdditionAlternativeList(Tokens,[]). %% parse_ExtensionAdditionAlternativeList([{'[[',_}|Rest],Acc) -> %% parse_ExtensionAdditionAlternativeList(Rest,Acc); %% parse_ExtensionAdditionAlternativeList(Tokens = [{identifier,_,_}|_Rest],Acc) -> %% {Element,Rest0} = parse_NamedType(Tokens); %% case Rest0 of %% [{',',_}|Rest01] -> %% parse_ExtensionAdditionAlternativeList(Rest01,[Element|Acc]); %% _ -> %% {lists:reverse([Element|Acc]),Rest0} %% end. %% parse_ExtensionAdditionAlternatives([{'[[',_}|Rest]) -> %% parse_ExtensionAdditionAlternatives(Rest,[]); %% parse_ExtensionAdditionAlternatives(Tokens) -> %% throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), %% [got,get_token(hd(Tokens)),expected,'[[']}}). %% parse_ExtensionAdditionAlternatives([Id = {identifier,_,_}|Rest],Acc) -> %% {NamedType, Rest2} = parse_NamedType([Id|Rest]), %% case Rest2 of %% [{',',_}|Rest21] -> %% parse_ExtensionAdditionAlternatives(Rest21,[NamedType|Acc]); %% [{']]',_}|Rest21] -> %% {lists:reverse(Acc),Rest21}; %% _ -> %% throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), %% [got,get_token(hd(Rest2)),expected,[',',']]']]}}) %% end. parse_NamedType([{identifier,L1,Idname}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#'ComponentType'{pos=L1,name=Idname,typespec=Type,prop=mandatory},Rest2}; parse_NamedType(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,identifier]}}). parse_ComponentTypeLists(Tokens) -> parse_ComponentTypeLists(Tokens,[]). parse_ComponentTypeLists(Tokens = [{identifier,_,_}|_Rest0],Clist) -> {CompList,Rest1} = parse_ComponentTypeList(Tokens,[]), parse_ComponentTypeLists(Rest1,Clist++CompList); parse_ComponentTypeLists(Tokens = [{'COMPONENTS',_},{'OF',_}|_Rest],Clist) -> {CompList,Rest1} = parse_ComponentTypeList(Tokens,[]), parse_ComponentTypeLists(Rest1,Clist++CompList); parse_ComponentTypeLists([{'...',L1},{'!',_}|Rest02],Clist0) -> {_,Rest03} = parse_ExceptionIdentification(Rest02), %% Exception info is currently thrown away parse_ComponentTypeLists2(Rest03,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_ComponentTypeLists([{',',L1},{'...',_},{'!',_}|Rest02],Clist0) when Clist0 =/= []-> {_,Rest03} = parse_ExceptionIdentification(Rest02), %% Exception info is currently thrown away parse_ComponentTypeLists2(Rest03,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_ComponentTypeLists([{',',_},{'...',L1}|Rest02],Clist0) when Clist0 =/= []-> parse_ComponentTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_ComponentTypeLists([{'...',L1}|Rest02],Clist0) -> parse_ComponentTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_ComponentTypeLists(Tokens = [{'}',_L1}|_Rest02],Clist0) -> {Clist0,Tokens}. parse_ComponentTypeLists2(Tokens,Clist) -> {ExtAdd,Rest} = parse_ExtensionAdditions(Tokens,Clist), {Clist2,Rest2} = parse_OptionalExtensionMarker(Rest,lists:flatten(ExtAdd)), case Rest2 of [{',',_}|Rest3] -> {CompList,Rest4} = parse_ComponentTypeList(Rest3,[]), {Clist2 ++ CompList,Rest4}; _ -> {Clist2,Rest2} end. parse_OptionalExtensionMarker([{',',_},{'...',L1}|Rest],Clist)-> {Clist++[#'EXTENSIONMARK'{pos=L1}],Rest}; parse_OptionalExtensionMarker(Tokens,Clist) -> {Clist,Tokens}. parse_ComponentTypeList([{',',_},Id = {identifier,_,_}|Rest],Acc) when Acc =/= [] -> {ComponentType,Rest2} = parse_ComponentType([Id|Rest]), parse_ComponentTypeList(Rest2,[ComponentType|Acc]); parse_ComponentTypeList([{',',_},C1={'COMPONENTS',_},C2={'OF',_}|Rest],Acc) when Acc =/= [] -> {ComponentType,Rest2} = parse_ComponentType([C1,C2|Rest]), parse_ComponentTypeList(Rest2,[ComponentType|Acc]); parse_ComponentTypeList(Tokens = [{'}',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ComponentTypeList(Tokens = [{']',_},{']',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ComponentTypeList(Tokens = [{',',_},{'...',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ComponentTypeList(Tokens,[]) -> {ComponentType,Rest} = parse_ComponentType(Tokens), parse_ComponentTypeList(Rest,[ComponentType]); parse_ComponentTypeList(Tokens,_) -> throw({asn1_error, {get_line(hd(Tokens)),get(asn1_module), [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))], expected,['}',', identifier']]}}). parse_ExtensionAdditions(Tokens=[{',',_}|_],Clist) -> {ExtAddList,Rest2} = parse_ExtensionAdditionList(Tokens,[]), {Clist++ExtAddList,Rest2}; parse_ExtensionAdditions(Tokens,Clist) -> %% Empty {Clist,Tokens}. parse_ExtensionAdditionList([{',',_},Id = {identifier,_,_}|Rest],Acc) -> {ComponentType,Rest2} = parse_ComponentType([Id|Rest]), parse_ExtensionAdditionList(Rest2,[ComponentType|Acc]); parse_ExtensionAdditionList([{',',_},C1={'COMPONENTS',_},C2={'OF',_}|Rest],Acc) -> {ComponentType,Rest2} = parse_ComponentType([C1,C2|Rest]), parse_ExtensionAdditionList(Rest2,[ComponentType|Acc]); parse_ExtensionAdditionList([{',',_},C1 = {'[',_},C2 = {'[',_}|Rest],Acc) -> {ExtAddGroup,Rest2} = parse_ExtensionAdditionGroup([C1,C2|Rest],[]), parse_ExtensionAdditionList(Rest2,[ExtAddGroup|Acc]); parse_ExtensionAdditionList(Tokens = [{'}',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ExtensionAdditionList(Tokens = [{',',_},{'...',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ExtensionAdditionList(Tokens,_) -> throw({asn1_error, {get_line(hd(Tokens)),get(asn1_module), [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))], expected,['}',', identifier']]}}). parse_ExtensionAdditionGroup([ {'[',_},{'[',_},_VsnNr = {number,_,Num},{':',_}|Rest],[]) -> parse_ExtensionAdditionGroup2(Rest,Num); parse_ExtensionAdditionGroup([ {'[',_},{'[',_}|Rest],[]) -> parse_ExtensionAdditionGroup2(Rest,undefined); parse_ExtensionAdditionGroup(Tokens,_) -> throw({asn1_error, {get_line(hd(Tokens)),get(asn1_module), [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))], expected,['[[']]}}). parse_ExtensionAdditionGroup2(Tokens,Num) -> {CompTypeList,Rest} = parse_ComponentTypeList(Tokens,[]), case Rest of [{']',_},{']',_}|Rest2] -> {[{'ExtensionAdditionGroup',Num}|CompTypeList] ++ ['ExtensionAdditionGroupEnd'],Rest2}; _ -> throw({asn1_error,{get_line(hd(Rest)),get(asn1_module), [got,get_token(hd(Rest)),expected,[']]']]}}) end. parse_ComponentType([{'COMPONENTS',_},{'OF',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {{'COMPONENTS OF',Type},Rest2}; parse_ComponentType(Tokens) -> Result = {NamedType,Rest} = parse_NamedType(Tokens), case Rest of [{'OPTIONAL',_}|Rest2] -> {NamedType#'ComponentType'{prop='OPTIONAL'},Rest2}; [{'DEFAULT',_}|Rest2] -> {Value,Rest21} = parse_Value(Rest2), {NamedType#'ComponentType'{prop={'DEFAULT',Value}},Rest21}; _ -> Result end. parse_SignedNumber([{number,_,Value}|Rest]) -> {Value,Rest}; parse_SignedNumber([{'-',_},{number,_,Value}|Rest]) -> {-Value,Rest}; parse_SignedNumber(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, [number,'-number']]}}). parse_Enumerations(Tokens=[{identifier,_,_}|_Rest],ExtensionDefault) -> parse_Enumerations(Tokens,[],ExtensionDefault); parse_Enumerations([H|_T],_) -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,identifier]}}). parse_Enumerations(Tokens = [{identifier,_,_},{'(',_}|_Rest], Acc, ExtensionDefault) -> {NamedNumber,Rest2} = parse_NamedNumber(Tokens), case Rest2 of [{',',_}|Rest3] -> parse_Enumerations(Rest3,[NamedNumber|Acc], ExtensionDefault); _ when ExtensionDefault == 'IMPLIED'-> {lists:reverse(['EXTENSIONMARK',NamedNumber|Acc]),Rest2}; _ -> {lists:reverse([NamedNumber|Acc]),Rest2} end; parse_Enumerations([{identifier,_,Id}|Rest], Acc, ExtensionDefault) -> case Rest of [{',',_}|Rest2] -> parse_Enumerations(Rest2,[Id|Acc], ExtensionDefault); _ when ExtensionDefault == 'IMPLIED' -> {lists:reverse(['EXTENSIONMARK', Id |Acc]),Rest}; _ -> {lists:reverse([Id|Acc]),Rest} end; parse_Enumerations([{'...',_}|Rest], Acc, _ExtensionDefault) -> case Rest of [{',',_}|Rest2] -> parse_Enumerations(Rest2,['EXTENSIONMARK'|Acc],undefined); _ -> {lists:reverse(['EXTENSIONMARK'|Acc]),Rest} end; parse_Enumerations([H|_T],_,_) -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,identifier]}}). parse_NamedNumberList(Tokens) -> parse_NamedNumberList(Tokens,[]). parse_NamedNumberList(Tokens,Acc) -> {NamedNum,Rest} = parse_NamedNumber(Tokens), case Rest of [{',',_}|Rest2] -> parse_NamedNumberList(Rest2,[NamedNum|Acc]); _ -> {lists:reverse([NamedNum|Acc]),Rest} end. parse_NamedNumber([{identifier,_,Name},{'(',_}|Rest]) -> Flist = [fun parse_SignedNumber/1, fun parse_DefinedValue/1], case (catch parse_or(Rest,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); {NamedNum,[{')',_}|Rest2]} -> {{'NamedNumber',Name,NamedNum},Rest2}; _ -> throw({asn1_error,{get_line(hd(Rest)),get(asn1_module), [got,get_token(hd(Rest)),expected,'NamedNumberList']}}) end; parse_NamedNumber(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,identifier]}}). parse_Tag([{'[',_}|Rest]) -> {Class,Rest2} = parse_Class(Rest), {ClassNumber,Rest3} = case Rest2 of [{number,_,Num}|Rest21] -> {Num,Rest21}; _ -> parse_DefinedValue(Rest2) end, case Rest3 of [{']',_}|Rest4] -> {#tag{class=Class,number=ClassNumber},Rest4}; _ -> throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module), [got,get_token(hd(Rest3)),expected,']']}}) end; parse_Tag(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'[']}}). parse_Class([{'UNIVERSAL',_}|Rest]) -> {'UNIVERSAL',Rest}; parse_Class([{'APPLICATION',_}|Rest]) -> {'APPLICATION',Rest}; parse_Class([{'PRIVATE',_}|Rest]) -> {'PRIVATE',Rest}; parse_Class(Tokens) -> {'CONTEXT',Tokens}. %% parse_Value(Tokens) -> Ret %% Tokens = [Tok] %% Tok = tuple() %% Ret = term() parse_Value(Tokens) -> Flist = [fun parse_BuiltinValue/1, fun parse_ValueFromObject/1, fun parse_DefinedValue/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end. parse_BuiltinValue([{bstring,_,Bstr}|Rest]) -> {{bstring,Bstr},Rest}; parse_BuiltinValue([{hstring,_,Hstr}|Rest]) -> {{hstring,Hstr},Rest}; parse_BuiltinValue([{'{',_},{'}',_}|Rest]) -> {[],Rest}; parse_BuiltinValue(Tokens = [{'{',_}|_Rest]) -> Flist = [ fun parse_SequenceOfValue/1, fun parse_SequenceValue/1, fun parse_ObjectIdentifierValue/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); Result -> Result end; parse_BuiltinValue([{identifier,_,IdName},{':',_}|Rest]) -> {Value,Rest2} = parse_Value(Rest), {{'CHOICE',{IdName,Value}},Rest2}; parse_BuiltinValue(Tokens=[{'NULL',_},{':',_}|_Rest]) -> parse_ObjectClassFieldValue(Tokens); parse_BuiltinValue([{'NULL',_}|Rest]) -> {'NULL',Rest}; parse_BuiltinValue([{'TRUE',_}|Rest]) -> {true,Rest}; parse_BuiltinValue([{'FALSE',_}|Rest]) -> {false,Rest}; parse_BuiltinValue([{'PLUS-INFINITY',_}|Rest]) -> {'PLUS-INFINITY',Rest}; parse_BuiltinValue([{'MINUS-INFINITY',_}|Rest]) -> {'MINUS-INFINITY',Rest}; parse_BuiltinValue([{cstring,_,Cstr}|Rest]) -> {Cstr,Rest}; parse_BuiltinValue([{number,_,Num}|Rest]) -> {Num,Rest}; parse_BuiltinValue([{'-',_},{number,_,Num}|Rest]) -> {- Num,Rest}; parse_BuiltinValue(Tokens) -> parse_ObjectClassFieldValue(Tokens). parse_DefinedValue(Tokens=[{identifier,_,_},{'{',_}|_Rest]) -> parse_ParameterizedValue(Tokens); %% Externalvaluereference parse_DefinedValue([{typereference,L1,Tname},{'.',_},{identifier,_,Idname}|Rest]) -> {#'Externalvaluereference'{pos=L1,module=Tname,value=Idname},Rest}; %% valuereference parse_DefinedValue([Id = {identifier,_,_}|Rest]) -> {identifier2Extvalueref(Id),Rest}; %% ParameterizedValue parse_DefinedValue(Tokens) -> parse_ParameterizedValue(Tokens). parse_SequenceValue([{'{',_}|Tokens]) -> parse_SequenceValue(Tokens,[]); parse_SequenceValue(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'{']}}). parse_SequenceValue([{identifier,_,IdName}|Rest],Acc) -> {Value,Rest2} = parse_Value(Rest), case Rest2 of [{',',_}|Rest3] -> parse_SequenceValue(Rest3,[{IdName,Value}|Acc]); [{'}',_}|Rest3] -> {lists:reverse([{IdName,Value}|Acc]),Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'}']}}) end; parse_SequenceValue(Tokens,_Acc) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,identifier]}}). parse_SequenceOfValue([{'{',_}|Tokens]) -> parse_SequenceOfValue(Tokens,[]); parse_SequenceOfValue(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'{']}}). parse_SequenceOfValue(Tokens,Acc) -> {Value,Rest2} = parse_Value(Tokens), case Rest2 of [{',',_}|Rest3] -> parse_SequenceOfValue(Rest3,[Value|Acc]); [{'}',_}|Rest3] -> {lists:reverse([Value|Acc]),Rest3}; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'}']}}) end. parse_ValueSetTypeAssignment([{typereference,L1,Name}|Rest]) -> {Type,Rest2} = parse_Type(Rest), case Rest2 of [{'::=',_}|Rest3] -> {ValueSet,Rest4} = parse_ValueSet(Rest3), {#valuedef{pos=L1,name=Name,type=Type,value=ValueSet, module=get(asn1_module)},Rest4}; [H|_T] -> throw({asn1_error,{get_line(L1),get(asn1_module), [got,get_token(H),expected,'::=']}}) end; parse_ValueSetTypeAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected, typereference]}}). parse_ValueSet([{'{',_}|Rest]) -> {Elems,Rest2} = parse_ElementSetSpecs(Rest), case Rest2 of [{'}',_}|Rest3] -> {{valueset,Elems},Rest3}; [H|_T] -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,'}']}}) end; parse_ValueSet(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'{']}}). parse_ValueAssignment([{identifier,L1,IdName}|Rest]) -> {Type,Rest2} = parse_Type(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Value,Rest4} = parse_Value(Rest3), case catch lookahead_assignment(Rest4) of ok -> {#valuedef{pos=L1,name=IdName,type=Type,value=Value, module=get(asn1_module)},Rest4}; Error -> throw(Error) %% throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), %% [got,get_token(hd(Rest2)),expected,'::=']}}) end; _ -> throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module), [got,get_token(hd(Rest2)),expected,'::=']}}) end; parse_ValueAssignment(Tokens) -> throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,identifier]}}). %% SizeConstraint parse_SubtypeElements([{'SIZE',_}|Tokens]) -> {Constraint,Rest} = parse_Constraint(Tokens), {{'SizeConstraint',Constraint#constraint.c},Rest}; %% PermittedAlphabet parse_SubtypeElements([{'FROM',_}|Tokens]) -> {Constraint,Rest} = parse_Constraint(Tokens), {{'PermittedAlphabet',Constraint#constraint.c},Rest}; %% InnerTypeConstraints parse_SubtypeElements([{'WITH',_},{'COMPONENT',_}|Tokens]) -> {Constraint,Rest} = parse_Constraint(Tokens), {{'WITH COMPONENT',Constraint},Rest}; parse_SubtypeElements([{'WITH',_},{'COMPONENTS',_},{'{',_},{'...',_},{',',_}|Tokens]) -> {Constraint,Rest} = parse_TypeConstraints(Tokens), case Rest of [{'}',_}|Rest2] -> {{'WITH COMPONENTS',{'PartialSpecification',Constraint}},Rest2}; _ -> throw({asn1_error,{get_line(hd(Rest)),get(asn1_module), [got,get_token(hd(Rest)),expected,'}']}}) end; parse_SubtypeElements([{'WITH',_},{'COMPONENTS',_},{'{',_}|Tokens]) -> {Constraint,Rest} = parse_TypeConstraints(Tokens), case Rest of [{'}',_}|Rest2] -> {{'WITH COMPONENTS',{'FullSpecification',Constraint}},Rest2}; _ -> throw({asn1_error,{get_line(hd(Rest)),get(asn1_module), [got,get_token(hd(Rest)),expected,'}']}}) end; parse_SubtypeElements([{'PATTERN',_}|Tokens]) -> {Value,Rest} = parse_Value(Tokens), {{pattern,Value},Rest}; %% SingleValue %% ContainedSubtype %% ValueRange %% TypeConstraint %% Moved fun parse_Value/1 and fun parse_Type/1 to parse_Elements parse_SubtypeElements(Tokens) -> Flist = [fun parse_ContainedSubtype/1, fun parse_Value/1, fun([{'MIN',_}|T]) -> {'MIN',T} end, fun parse_Type/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); {asn1_error,Reason} -> throw(Reason); Result = {Val,_} when is_record(Val,type) -> Result; {Lower,[{'..',_}|Rest]} -> {Upper,Rest2} = parse_UpperEndpoint(Rest), {{'ValueRange',{Lower,Upper}},Rest2}; {Lower,[{'<',_},{'..',_}|Rest]} -> {Upper,Rest2} = parse_UpperEndpoint(Rest), {{'ValueRange',{{gt,Lower},Upper}},Rest2}; {Res={'ContainedSubtype',_Type},Rest} -> {Res,Rest}; {Value,Rest} -> {{'SingleValue',Value},Rest} end. parse_ContainedSubtype([{'INCLUDES',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {{'ContainedSubtype',Type},Rest2}; parse_ContainedSubtype(Tokens) -> throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module), [got,get_token(hd(Tokens)),expected,'INCLUDES']}}). %%parse_ContainedSubtype(Tokens) -> %this option is moved to parse_SubtypeElements %% parse_Type(Tokens). parse_UpperEndpoint([{'<',_}|Rest]) -> parse_UpperEndpoint(lt,Rest); parse_UpperEndpoint(Tokens) -> parse_UpperEndpoint(false,Tokens). parse_UpperEndpoint(Lt,Tokens) -> Flist = [ fun([{'MAX',_}|T]) -> {'MAX',T} end, fun parse_Value/1], case (catch parse_or(Tokens,Flist)) of {'EXIT',Reason} -> exit(Reason); AsnErr = {asn1_error,_} -> throw(AsnErr); {Value,Rest2} when Lt == lt -> {{lt,Value},Rest2}; {Value,Rest2} -> {Value,Rest2} end. parse_TypeConstraints(Tokens) -> parse_TypeConstraints(Tokens,[]). parse_TypeConstraints([{identifier,_,_}|Rest],Acc) -> {ComponentConstraint,Rest2} = parse_ComponentConstraint(Rest), case Rest2 of [{',',_}|Rest3] -> parse_TypeConstraints(Rest3,[ComponentConstraint|Acc]); _ -> {lists:reverse([ComponentConstraint|Acc]),Rest2} end; parse_TypeConstraints([H|_T],_) -> throw({asn1_error,{get_line(H),get(asn1_module), [got,get_token(H),expected,identifier]}}). parse_ComponentConstraint(Tokens = [{'(',_}|_Rest]) -> {ValueConstraint,Rest2} = parse_Constraint(Tokens), {PresenceConstraint,Rest3} = parse_PresenceConstraint(Rest2), {{ValueConstraint,PresenceConstraint},Rest3}; parse_ComponentConstraint(Tokens) -> {PresenceConstraint,Rest} = parse_PresenceConstraint(Tokens), {{asn1_empty,PresenceConstraint},Rest}. parse_PresenceConstraint([{'PRESENT',_}|Rest]) -> {'PRESENT',Rest}; parse_PresenceConstraint([{'ABSENT',_}|Rest]) -> {'ABSENT',Rest}; parse_PresenceConstraint([{'OPTIONAL',_}|Rest]) -> {'OPTIONAL',Rest}; parse_PresenceConstraint(Tokens) -> {asn1_empty,Tokens}. % merge_constraints({Rlist,ExtList}) -> % extensionmarker in constraint % {merge_constraints(Rlist,[],[]), % merge_constraints(ExtList,[],[])}; %% An arg with a constraint with extension marker will look like %% [#constraint{c={Root,Ext}}|Rest] merge_constraints(Clist) -> merge_constraints(Clist, [], []). merge_constraints([Ch|Ct],Cacc, Eacc) -> NewEacc = case Ch#constraint.e of undefined -> Eacc; E -> [E|Eacc] end, merge_constraints(Ct,[fixup_constraint(Ch#constraint.c)|Cacc],NewEacc); merge_constraints([],Cacc,[]) -> %% lists:flatten(Cacc); lists:reverse(Cacc); merge_constraints([],Cacc,Eacc) -> %% lists:flatten(Cacc) ++ [{'Errors',Eacc}]. lists:reverse(Cacc) ++ [{'Errors',Eacc}]. fixup_constraint(C) -> case C of {'SingleValue',SubType} when element(1,SubType) == 'ContainedSubtype' -> SubType; {'SingleValue',V} when is_list(V) -> C; %% [C,{'ValueRange',{lists:min(V),lists:max(V)}}]; %% bug, turns wrong when an element in V is a reference to a defined value {'PermittedAlphabet',{'SingleValue',V}} when is_list(V) -> %%sort and remove duplicates V2 = {'SingleValue', ordsets:from_list(lists:flatten(V))}, {'PermittedAlphabet',V2}; {'PermittedAlphabet',{'SingleValue',V}} -> V2 = {'SingleValue',[V]}, {'PermittedAlphabet',V2}; {'SizeConstraint',Sc} -> {'SizeConstraint',fixup_size_constraint(Sc)}; List when is_list(List) -> %% In This case maybe a union or intersection [fixup_constraint(Xc)||Xc <- List]; Other -> Other end. fixup_size_constraint({'ValueRange',{Lb,Ub}}) -> {Lb,Ub}; fixup_size_constraint({{'ValueRange',R},[]}) -> {R,[]}; fixup_size_constraint({[],{'ValueRange',R}}) -> {[],R}; fixup_size_constraint({{'ValueRange',R1},{'ValueRange',R2}}) -> {R1,R2}; fixup_size_constraint({'SingleValue',[Sv]}) -> fixup_size_constraint({'SingleValue',Sv}); fixup_size_constraint({'SingleValue',L}) when is_list(L) -> ordsets:from_list(L); fixup_size_constraint({'SingleValue',L}) -> {L,L}; fixup_size_constraint({'SizeConstraint',C}) -> %% this is a second SIZE fixup_size_constraint(C); fixup_size_constraint({C1,C2}) -> %% this is with extension marks {turn2vr(fixup_size_constraint(C1)), extension_size(fixup_size_constraint(C2))}; fixup_size_constraint(CList) when is_list(CList) -> [fixup_constraint(Xc)||Xc <- CList]. turn2vr(L) when is_list(L) -> L2 =[X||X<-ordsets:from_list(L),is_integer(X)], case L2 of [H|_] -> {H,hd(lists:reverse(L2))}; _ -> L end; turn2vr(VR) -> VR. extension_size({I,I}) -> [I]; extension_size({I1,I2}) -> [I1,I2]; extension_size(C) -> C. get_line({_,Pos,Token}) when is_integer(Pos),is_atom(Token) -> Pos; get_line({Token,Pos}) when is_integer(Pos),is_atom(Token) -> Pos; get_line(_) -> undefined. get_token({_,Pos,Token}) when is_integer(Pos),is_atom(Token) -> Token; get_token({'$end',Pos}) when is_integer(Pos) -> undefined; get_token({Token,Pos}) when is_integer(Pos),is_atom(Token) -> Token; get_token(_) -> undefined. prioritize_error(ErrList) -> case lists:keymember(asn1_error,1,ErrList) of false -> % only asn1_assignment_error -> take the last lists:last(ErrList); true -> % contains errors from deeper in a Type NewErrList = [_Err={_,_}|_RestErr] = lists:filter(fun({asn1_error,_})->true;(_)->false end, ErrList), SplitErrs = lists:splitwith(fun({_,X})-> case element(1,X) of Int when is_integer(Int) -> true; _ -> false end end, NewErrList), case SplitErrs of {[],UndefPosErrs} -> % if no error with Positon exists lists:last(UndefPosErrs); {IntPosErrs,_} -> IntPosReasons = lists:map(fun(X)->element(2,X) end,IntPosErrs), SortedReasons = lists:keysort(1,IntPosReasons), {asn1_error,lists:last(SortedReasons)} end end. %% most_prio_error([H={_,Reason}|T],Atom,Err) when is_atom(Atom) -> %% most_prio_error(T,element(1,Reason),H); %% most_prio_error([H={_,Reason}|T],Greatest,Err) -> %% case element(1,Reason) of %% Pos when is_integer(Pos),Pos>Greatest -> %% most_prio_error( tref2Exttref(#typereference{pos=Pos,val=Name}) -> #'Externaltypereference'{pos=Pos, module=resolve_module(Name), type=Name}. tref2Exttref(Pos,Name) -> #'Externaltypereference'{pos=Pos, module=resolve_module(Name), type=Name}. identifier2Extvalueref(#identifier{pos=Pos,val=Name}) -> #'Externalvaluereference'{pos=Pos, module=resolve_module(Name), value=Name}. %% lookahead_assignment/1 checks that the next sequence of tokens %% in Token contain a valid assignment or the %% 'END' token. Otherwise an exception is thrown. lookahead_assignment([{'END',_}|_Rest]) -> ok; lookahead_assignment(Tokens) -> parse_Assignment(Tokens), ok. is_pre_defined_class('TYPE-IDENTIFIER') -> true; is_pre_defined_class('ABSTRACT-SYNTAX') -> true; is_pre_defined_class(_) -> false.