| 947 | * @private Visible for testing only. |
| 948 | */ |
| 949 | export function parseActionMap(action, context) { |
| 950 | const assertAction = assertActionForParser.bind(null, action, context); |
| 951 | const assertToken = assertTokenForParser.bind(null, action, context); |
| 952 | |
| 953 | let actionMap = null; |
| 954 | |
| 955 | const toks = new ParserTokenizer(action); |
| 956 | let tok; |
| 957 | let peek; |
| 958 | do { |
| 959 | tok = toks.next(); |
| 960 | if ( |
| 961 | tok.type == TokenType_Enum.EOF || |
| 962 | (tok.type == TokenType_Enum.SEPARATOR && tok.value == ';') |
| 963 | ) { |
| 964 | // Expected, ignore. |
| 965 | } else if ( |
| 966 | tok.type == TokenType_Enum.LITERAL || |
| 967 | tok.type == TokenType_Enum.ID |
| 968 | ) { |
| 969 | // Format: event:target.method |
| 970 | |
| 971 | // Event: "event:" |
| 972 | const event = tok.value; |
| 973 | |
| 974 | // Target: ":target." separator |
| 975 | assertToken(toks.next(), [TokenType_Enum.SEPARATOR], ':'); |
| 976 | |
| 977 | const actions = []; |
| 978 | |
| 979 | // Handlers for event. |
| 980 | do { |
| 981 | const target = assertToken(toks.next(), [ |
| 982 | TokenType_Enum.LITERAL, |
| 983 | TokenType_Enum.ID, |
| 984 | ]).value; |
| 985 | |
| 986 | // Method: ".method". Method is optional. |
| 987 | let method = DEFAULT_ACTION; |
| 988 | let args = null; |
| 989 | |
| 990 | peek = toks.peek(); |
| 991 | if (peek.type == TokenType_Enum.SEPARATOR && peek.value == '.') { |
| 992 | toks.next(); // Skip '.' |
| 993 | method = |
| 994 | assertToken(toks.next(), [ |
| 995 | TokenType_Enum.LITERAL, |
| 996 | TokenType_Enum.ID, |
| 997 | ]).value || method; |
| 998 | |
| 999 | // Optionally, there may be arguments: "(key = value, key = value)". |
| 1000 | peek = toks.peek(); |
| 1001 | if (peek.type == TokenType_Enum.SEPARATOR && peek.value == '(') { |
| 1002 | toks.next(); // Skip '(' |
| 1003 | args = tokenizeMethodArguments(toks, assertToken, assertAction); |
| 1004 | } |
| 1005 | } |
| 1006 | |