package com.five35.dex;

import com.google.common.base.Preconditions;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;

/**
 * A valid symbol in Dex.
 */
@Immutable
public abstract class Symbol {
	private static final Map<String, Symbol> SYMBOL_TABLE = new HashMap<>();

	private final int leftBindingPower;
	private final String name;

	Symbol(final String name, final int leftBindingPower) {
		this.name = Preconditions.checkNotNull(name);
		this.leftBindingPower = leftBindingPower;
	}

	Symbol(final String name, final String characters, final int leftBindingPower) {
		this(name, leftBindingPower);

		Symbol.SYMBOL_TABLE.put(characters, this);
	}

	@Nonnull
	static Symbol getSymbol(final Token token) throws InvalidSymbolException {
		final String characters = Preconditions.checkNotNull(token).toString();

		if (Symbol.SYMBOL_TABLE.containsKey(characters)) {
			return Symbol.SYMBOL_TABLE.get(characters);
		}

		// TODO: recognize variable names and numbers

		throw new InvalidSymbolException(characters);
	}

	@Nonnull
	abstract Expression denoteLeft(final Parser parser, final Expression left) throws ParserException;

	@Nonnull
	abstract Expression denoteNull(final Parser parser) throws ParserException;

	int getLeftBindingPower() {
		return this.leftBindingPower;
	}

	@Override
	@Nonnull
	public String toString() {
		return this.name;
	}
}

@@ -342,16 +342,963 @@
 p%3C%3E();%0A%0A
+%09static final Symbol OPERATOR_ADD = new InfixSymbol(%22OPERATOR_ADD%22, %22+%22, 10) %7B%0A%09%09@Override%0A%09%09Result binary(final Result left, final Result right) %7B%0A%09%09%09return new ScalarResult(left.asFloat() + left.asFloat());%0A%09%09%7D%0A%09%7D;%0A%0A%09// TODO: needs to work as a unary operator, too%0A%09static final Symbol OPERATOR_SUBTRACT = new InfixSymbol(%22OPERATOR_SUBTRACT%22, %22-%22, 10) %7B%0A%09%09@Override%0A%09%09Result binary(final Result left, final Result right) %7B%0A%09%09%09return new ScalarResult(left.asFloat() - left.asFloat());%0A%09%09%7D%0A%09%7D;%0A%0A%09static final Symbol OPERATOR_MULTIPLY = new InfixSymbol(%22OPERATOR_MULTIPLY%22, %22*%22, 20) %7B%0A%09%09@Override%0A%09%09Result binary(final Result left, final Result right) %7B%0A%09%09%09return new ScalarResult(left.asFloat() * left.asFloat());%0A%09%09%7D%0A%09%7D;%0A%0A%09static final Symbol OPERATOR_DIVIDE = new InfixSymbol(%22OPERATOR_DIVIDE%22, %22/%22, 20) %7B%0A%09%09@Override%0A%09%09Result binary(final Result left, final Result right) %7B%0A%09%09%09return new ScalarResult(left.asFloat() / left.asFloat());%0A%09%09%7D%0A%09%7D;%0A%0A
 %09private

add basic arithmetic operators