package compiler; import compiler.macros.MacroInterface; import grammar.Expression; import grammar.Expression.MacroRule; import grammar.Expression.Rule; import grammar.Grammar; import parser.Match; import static util.ListUtils.list; /** * Describes a macro defined in a macro file. */ public class Macro { /****************************************************************************/ public final Rule parentRule; /****************************************************************************/ public final Grammar grammar; /****************************************************************************/ public final Rule rule; /****************************************************************************/ private boolean enabled; /****************************************************************************/ public final boolean raw; /****************************************************************************/ public final boolean prioritary; /****************************************************************************/ private final MacroInterface expander; /****************************************************************************/ public enum Strategy { AS, UNDER, REPLACES, CALLED } /****************************************************************************/ private Strategy strategy; /****************************************************************************/ public Macro( String ruleName, Rule parentRule, Grammar grammar, Expression syntax, MacroInterface expander, Strategy strategy, boolean raw, boolean prioritary) { this.parentRule = parentRule; this.grammar = grammar; this.expander = expander; this.strategy = strategy; this.raw = raw; this.prioritary = prioritary; this.enabled = false; if (expander == null && strategy != Strategy.CALLED) { throw new Error("No body for macro " + ruleName + ". Maybe you meant to use the \"called\" strategy?"); } if ((parentRule == null) != (strategy== Strategy.CALLED)) { throw new Error("Mismatch between strategy " + strategy + " and the " + (parentRule == null ? "absence" : "presence") + " of a parent rule in macro " + ruleName + "."); } Rule dirty = expander == null ? new Rule(ruleName, list(syntax)) : new MacroRule(ruleName, this, syntax); this.rule = grammar.cleanUnregisteredRule(dirty); } /****************************************************************************/ public Macro( String ruleName, String parentRule, Grammar grammar, Expression syntax, MacroInterface expander, Strategy strategy, boolean raw, boolean prioritary) { this(ruleName, parentRule == null ? null : grammar.rule(parentRule), grammar, syntax, expander, strategy, raw, prioritary); } /****************************************************************************/ @Override public String toString() { return rule.name; } /****************************************************************************/ public Match expand(Match match) { return expander == null ? match : expander.expand(match); } /***************************************************************************** * Enables the macro, adding it to the grammar. */ public void enable() { assert !enabled; if (parentRule != null) { grammar.addRuleAlternative(parentRule, rule, prioritary); } else { grammar.registerRule(rule); } enabled = true; } /***************************************************************************** * Disables the macro, removing it from the grammar. */ public void disable() { assert enabled; if (parentRule != null) { grammar.removeRuleAlternative(parentRule, rule); } else { grammar.unregisterRule(rule); } enabled = false; } /****************************************************************************/ public void ensureDisabled() { if (enabled) { disable(); } } /****************************************************************************/ public Strategy strategy() { return strategy; } /****************************************************************************/ public boolean isAs() { return strategy == Strategy.AS; } /****************************************************************************/ public boolean isUnder() { return strategy == Strategy.UNDER; } /****************************************************************************/ public boolean isReplaces() { return strategy == Strategy.REPLACES; } /****************************************************************************/ public boolean isCalled() { return strategy == Strategy.CALLED; } }