/*******************************************************************************
 * Copyright (c) 2015 Bruno Medeiros and other Contributors.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Bruno Medeiros - initial API and implementation
 *******************************************************************************/
package com.github.rustdt.tooling.lexer;

import static melnorme.utilbox.core.CoreUtil.areEqual;

import melnorme.lang.tooling.parser.lexer.CharacterReader_SubReader;
import melnorme.lang.tooling.parser.lexer.WordLexerRule;
import melnorme.lang.utils.parse.ICharacterReader;
import melnorme.lang.utils.parse.LexingUtils;

/**
 * A lexer rule used for coloring purposes.
 */
public class RustWordLexerRule extends WordLexerRule<RustColoringTokens> {
	
	public static final String[] keywords_control = { 
			"abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", 
			"do", "else", "enum", "extern", "final", "fn", "for", "if", "impl", "in", "let", 
			"loop", "macro", "match", "mod", "move", "mut", "offsetof", "override", 
			"priv", "proc", "pub", "pure", "ref", "return", "sizeof", "static", "struct", 
			"trait", "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield" 
	};
	public static final String[] keywords_boolean_lit = { 
			"true", "false",
	};
	public static final String[] keywords_self = { 
			"self", "Self", "super"
	};
	
	/* -----------------  ----------------- */
	
	protected final RustNumberLexingRule rustNumberLexingRule = new RustNumberLexingRule();
	
	public RustWordLexerRule() {
		super(RustColoringTokens.WS, RustColoringTokens.WORD);
		
		addKeywords(RustColoringTokens.KEYWORD, RustWordLexerRule.keywords_control);
		addKeywords(RustColoringTokens.KEYWORD_BOOL, RustWordLexerRule.keywords_boolean_lit);
		addKeywords(RustColoringTokens.KEYWORD_SELF, RustWordLexerRule.keywords_self);
	}
	
	@Override
	public RustColoringTokens doEvaluateToken(ICharacterReader reader) {
		if(reader.tryConsume('?')) {
			return RustColoringTokens.TRY_OP;
		}
		
		RustColoringTokens result = super.doEvaluateToken(reader);
		
		if(result == null) {
			if(rustNumberLexingRule.tryMatch(reader)) {
				return RustColoringTokens.NUMBER;
			}
		}
		
		if(result != defaultWordToken) {
			return result;
		}
		// We found a word then. Let's see if it's a macro invocation
		
		CharacterReader_SubReader subReader = new CharacterReader_SubReader(reader); 
		LexingUtils.skipWhitespace(subReader);
		if(subReader.tryConsume('!')) {
			
			int afterWS = LexingUtils.countWhitespace(subReader);
			int lookahead = subReader.lookahead(afterWS);
			if(areEqual(lastEvaluatedWord, "macro_rules")) {
				subReader.consumeInParentReader();
				return RustColoringTokens.MACRO_RULES;
			}
			if(lookahead == '(' || lookahead == '[') {
				subReader.consumeInParentReader();
				return RustColoringTokens.MACRO_CALL;
			}
		}
		return result;
	}
	
}