[440] | 1 | package com.framsticks.framclipse; |
---|
| 2 | |
---|
| 3 | import org.antlr.runtime.CharStream; |
---|
| 4 | import org.antlr.runtime.RecognitionException; |
---|
| 5 | import org.antlr.runtime.Token; |
---|
| 6 | |
---|
| 7 | import com.framsticks.framclipse.parser.antlr.internal.InternalFramScriptLexer; |
---|
| 8 | |
---|
| 9 | public class FramScriptAuxiliaryLexer extends InternalFramScriptLexer { |
---|
| 10 | |
---|
| 11 | private static final int FLG_MULTILINE = 0x1; |
---|
| 12 | private static final int FLG_TYPE_IS_NUMERIC = 0x2; // if raised, the default value should be analysed with internal lexer |
---|
| 13 | private static final int FLG_TYPE_IS_STRING = 0x4; // if raised, the max value can be omitted and should be 0 |
---|
| 14 | private static final int CTX_NONE = 0; |
---|
| 15 | private static final int CTX_TYPE = 1; |
---|
| 16 | private static final int CTX_TYPE_ID = 2; |
---|
| 17 | private static final int CTX_TYPE_MIN = 3; |
---|
| 18 | private static final int CTX_TYPE_MAX = 4; |
---|
| 19 | private static final int CTX_TYPE_DEFAULT = 5; |
---|
| 20 | |
---|
| 21 | private int context = CTX_NONE; |
---|
| 22 | private int flags = 0; |
---|
| 23 | private Token previous = Token.INVALID_TOKEN; |
---|
| 24 | |
---|
| 25 | private void checkML() { |
---|
| 26 | setFlag(FLG_MULTILINE, next() == '~'); |
---|
| 27 | } |
---|
| 28 | |
---|
| 29 | private boolean isSet(int flag) { |
---|
| 30 | return (flags & flag) != 0; |
---|
| 31 | } |
---|
| 32 | |
---|
| 33 | private void setFlag(int flag, boolean state) { |
---|
| 34 | if (state) |
---|
| 35 | flags |= flag; |
---|
| 36 | else |
---|
| 37 | flags &= ~flag; |
---|
| 38 | } |
---|
| 39 | |
---|
| 40 | private void setState(int tokenType) { |
---|
| 41 | state.token = null; |
---|
| 42 | state.channel = Token.DEFAULT_CHANNEL; |
---|
| 43 | state.tokenStartCharIndex = input.index(); |
---|
| 44 | state.tokenStartCharPositionInLine = input.getCharPositionInLine(); |
---|
| 45 | state.tokenStartLine = input.getLine(); |
---|
| 46 | state.text = null; |
---|
| 47 | state.type = tokenType; |
---|
| 48 | } |
---|
| 49 | |
---|
| 50 | char next() { |
---|
| 51 | return next(1); |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | char next(int i) { |
---|
| 55 | return (char)input.LA(i); |
---|
| 56 | } |
---|
| 57 | |
---|
| 58 | void consumeUntilAny(String term) { |
---|
| 59 | term += (char)CharStream.EOF; |
---|
| 60 | while (term.indexOf(next()) == -1) |
---|
| 61 | matchAny(); |
---|
| 62 | } |
---|
| 63 | |
---|
| 64 | @Override |
---|
| 65 | public Token nextToken() { |
---|
| 66 | switch (previous.getType()) { |
---|
| 67 | case RULE_HEADER_ID: |
---|
| 68 | setState(RULE_HEADER_VALUE); |
---|
| 69 | checkML(); |
---|
| 70 | mHEADER_VALUE(); |
---|
| 71 | return previous = emit(); |
---|
| 72 | case RULE_TYPE_HEADER: |
---|
| 73 | checkML(); |
---|
| 74 | context = CTX_TYPE; |
---|
| 75 | if (isSet(FLG_MULTILINE)) { |
---|
| 76 | setState(RULE_WS); // any ignored token |
---|
| 77 | matchAny(); // consume '~' |
---|
| 78 | return previous = emit(); |
---|
| 79 | } |
---|
| 80 | break; |
---|
| 81 | case RULE_WS: |
---|
| 82 | if (context == CTX_TYPE_MIN) { |
---|
| 83 | if (isSet(FLG_TYPE_IS_STRING)) { |
---|
| 84 | if (!Character.isDigit(next()) && next() != '-') { // if string length is omitted |
---|
| 85 | if (isSet(FLG_MULTILINE)) |
---|
| 86 | matchAny(); // ignore expected '~' |
---|
| 87 | setState(RULE_INT); |
---|
| 88 | state.text = "0"; // pretend the max value is 0 |
---|
| 89 | return previous = emit(); |
---|
| 90 | } |
---|
| 91 | } |
---|
| 92 | } |
---|
| 93 | if (previous.getText().indexOf('\n') != -1 || |
---|
| 94 | previous.getText().indexOf('\r') != -1) { |
---|
| 95 | if (!isSet(FLG_MULTILINE)) { |
---|
| 96 | context = CTX_NONE; |
---|
| 97 | } |
---|
| 98 | // workaround for '#include' |
---|
| 99 | if (willMatch("#include")) { |
---|
| 100 | setState(RULE_PROP_INCLUDE); |
---|
| 101 | try { |
---|
| 102 | mRULE_PROP_INCLUDE(); |
---|
| 103 | } catch (RecognitionException e) { |
---|
| 104 | reportError(e); |
---|
| 105 | } |
---|
| 106 | return previous = emit(); |
---|
| 107 | } |
---|
| 108 | if (!isSet(FLG_MULTILINE)) { |
---|
| 109 | break; |
---|
| 110 | } |
---|
| 111 | } |
---|
| 112 | if (context == CTX_TYPE_MAX) { |
---|
| 113 | if (isSet(FLG_MULTILINE)) { |
---|
| 114 | context = CTX_TYPE_DEFAULT; |
---|
| 115 | } else { |
---|
| 116 | context = CTX_NONE; |
---|
| 117 | } |
---|
| 118 | if (isSet(FLG_TYPE_IS_NUMERIC)) { |
---|
| 119 | if (isSet(FLG_MULTILINE) && !Character.isDigit(next()) |
---|
| 120 | && next() != '-') { // if default value is omitted |
---|
| 121 | previous = aux_ENUM_LITERAL(); |
---|
| 122 | if (previous != null) |
---|
| 123 | return previous; |
---|
| 124 | } |
---|
| 125 | break; |
---|
| 126 | } else { |
---|
| 127 | setState(RULE_HEADER_VALUE); |
---|
| 128 | mRULE_TYPE_HEADER_VALUE(); |
---|
| 129 | return previous = emit(); |
---|
| 130 | } |
---|
| 131 | } else if (context == CTX_TYPE_DEFAULT) { |
---|
| 132 | previous = aux_ENUM_LITERAL(); |
---|
| 133 | if (previous != null) |
---|
| 134 | return previous; |
---|
| 135 | } |
---|
| 136 | break; |
---|
| 137 | case RULE_ID: |
---|
| 138 | if (context == CTX_TYPE) { |
---|
| 139 | if ("df".indexOf(previous.getText().charAt(0)) == -1) { |
---|
| 140 | setFlag(FLG_TYPE_IS_NUMERIC, false); |
---|
| 141 | setFlag(FLG_TYPE_IS_STRING, previous.getText().charAt(0) == (int)'s'); |
---|
| 142 | } else { |
---|
| 143 | setFlag(FLG_TYPE_IS_NUMERIC, true); |
---|
| 144 | } |
---|
| 145 | context = CTX_TYPE_ID; |
---|
| 146 | break; |
---|
| 147 | } |
---|
| 148 | context = CTX_NONE; |
---|
| 149 | break; |
---|
| 150 | case RULE_HEADER_VALUE: |
---|
| 151 | case RULE_ENUM_LITERAL: |
---|
| 152 | if (context == CTX_TYPE_DEFAULT) { |
---|
| 153 | previous = aux_ENUM_LITERAL(); |
---|
| 154 | if (previous != null) |
---|
| 155 | return previous; |
---|
| 156 | } |
---|
| 157 | context = CTX_NONE; |
---|
| 158 | break; |
---|
| 159 | case RULE_DOUBLE: |
---|
| 160 | case RULE_INT: |
---|
| 161 | if (context == CTX_TYPE_DEFAULT) { |
---|
| 162 | break; // avoid changing context |
---|
| 163 | } else if (context == CTX_TYPE_ID) { |
---|
| 164 | context = CTX_TYPE_MIN; |
---|
| 165 | break; |
---|
| 166 | } else if (context == CTX_TYPE_MIN) { |
---|
| 167 | context = CTX_TYPE_MAX; |
---|
| 168 | break; |
---|
| 169 | } |
---|
| 170 | context = CTX_NONE; |
---|
| 171 | break; |
---|
| 172 | default: |
---|
| 173 | if ("-".equals(previous.getText()) || |
---|
| 174 | "+".equals(previous.getText())) { |
---|
| 175 | break; |
---|
| 176 | } |
---|
| 177 | context = CTX_NONE; |
---|
| 178 | case RULE_SL_COMMENT: |
---|
| 179 | break; |
---|
| 180 | } |
---|
| 181 | return previous = super.nextToken(); |
---|
| 182 | } |
---|
| 183 | |
---|
| 184 | private boolean willMatch(String string) { |
---|
| 185 | for (int i = 0; i < string.length(); ++i) { |
---|
| 186 | if (next(i+1) != string.charAt(i)) |
---|
| 187 | return false; |
---|
| 188 | } |
---|
| 189 | return true; |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | private Token aux_ENUM_LITERAL() { |
---|
| 193 | // CTX_TYPE_DEFAULT assumes raised FLG_MULTILINE |
---|
| 194 | if (next() == '~') { |
---|
| 195 | setState(RULE_WS); // any ignored token |
---|
| 196 | matchAny(); |
---|
| 197 | context = CTX_NONE; |
---|
| 198 | return emit(); |
---|
| 199 | } else if (next() == '\\' && next(2) == '~') { |
---|
| 200 | matchAny(); // not assigned to any terminal |
---|
| 201 | setState(RULE_ENUM_LITERAL); |
---|
| 202 | matchAny(); // consume '~' |
---|
| 203 | mRULE_TYPE_HEADER_VALUE(); |
---|
| 204 | return emit(); |
---|
| 205 | } |
---|
| 206 | return null; |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | private void mRULE_TYPE_HEADER_VALUE() { |
---|
| 210 | if (isSet(FLG_MULTILINE)) { |
---|
| 211 | do { |
---|
| 212 | consumeUntilAny("\\~"); |
---|
| 213 | if (next() == '\\' && next(2) != '~') { |
---|
| 214 | matchAny(); |
---|
| 215 | continue; |
---|
| 216 | } |
---|
| 217 | } while (false); |
---|
| 218 | } else { |
---|
| 219 | consumeUntilAny("~\r\n"); |
---|
| 220 | } |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | private void mHEADER_VALUE() { |
---|
| 224 | if (isSet(FLG_MULTILINE)) { |
---|
| 225 | matchAny(); // consume '~' |
---|
| 226 | do { |
---|
| 227 | consumeUntilAny("\\~"); |
---|
| 228 | if (next() == '\\') { |
---|
| 229 | matchAny(); |
---|
| 230 | if (next() == '~') |
---|
| 231 | matchAny(); |
---|
| 232 | continue; |
---|
| 233 | } |
---|
| 234 | } while (false); |
---|
| 235 | matchAny(); |
---|
| 236 | } else { |
---|
| 237 | consumeUntilAny("\r\n"); |
---|
| 238 | } |
---|
| 239 | } |
---|
| 240 | } |
---|