Tracer.java
/*
* Copyright 2013 Michael Mackenzie High
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mackenziehigh.snowflake;
import java.util.LinkedList;
/**
* An instance of this class facilitates the recording of a bounded number of match attempts.
*
* @author Mackenzie High
*/
final class Tracer
{
/**
* These are the rules in the bounded queue.
*/
private final Rule[] rules;
/**
* These are the start-positions in the bounded queue.
*/
private final int[] starts;
/**
* These are the reasons in the bounded queue.
*/
private final TraceElementReason[] reasons;
/**
* This is the index of the most-recently added element in the bounded queue.
*/
private int most_recent = 0;
/**
* This is the actual number of elements that are currently in the bounded queue.
*/
private int count;
/**
* This is the total number of elements that have been added to the bounded-queue.
*/
private int total = 0;
/**
* Sole Constructor
*
* @param size is the maximum number of trace-elements that are stored at any given time.
* @throws IllegalArgumentException <code>if size < 0</code>
*/
Tracer(int size)
{
if(size < 0) { throw new IllegalArgumentException(); }
this.reasons = new TraceElementReason[size];
this.starts = new int[size];
this.rules = new Rule[size];
}
/**
* This function adds another record to the backtrace.
*
* @param rule is the rule that is attempting to match.
* @param start is the location where the parser began attempting to match.
* @param reason is the reason why the record is being created.
*/
final void add(final Rule rule, final int start, TraceElementReason result)
{
++total;
if(rules.length == 0) { return; }
// The bounded queue is implemented using arrays.
// Therefore, keep track of of which element is at the front of the queue.
most_recent = most_recent + 1 == rules.length ? 0 : most_recent + 1;
// The bounded queue cannot store more than the maximum number of elements.
count = count == rules.length ? count : count + 1;
// Multiple array elements are used to store the value of a single element in the queue.
this.rules[most_recent] = rule;
this.starts[most_recent] = start;
this.reasons[most_recent] = result;
}
/**
* This method returns an immutable representation of the current state of this object.
*
* @return the aforedescribed object.
*/
public Trace output()
{
final LinkedList<TraceElement> list = new LinkedList<TraceElement>();
int index = most_recent;
for(int i = 0; i < count; i++)
{
list.addFirst(new TraceElement(rules[index].name(), starts[index], reasons[index]));
index = index == 0 ? rules.length - 1 : index - 1;
}
return new Trace(list, total);
}
}