use of com.squarespace.template.Instructions.EvalInst in project template-compiler by Squarespace.
the class Tokenizer method parseInstruction.
/**
* We've found the start of an instruction. Parse the rest of the range.
*/
private boolean parseInstruction(InstructionType type, int start, int end) throws CodeSyntaxException {
switch(type) {
case ALTERNATES_WITH:
// Look for SPACE "WITH" EOF
if (!matcher.space()) {
fail(error(SyntaxErrorType.WHITESPACE_EXPECTED).data(matcher.remainder()));
return emitInvalid();
}
matcher.consume();
if (!matcher.wordWith()) {
fail(error(MISSING_WITH_KEYWORD).data(matcher.remainder()));
return emitInvalid();
}
matcher.consume();
if (!matcher.finished()) {
fail(error(EXTRA_CHARS).type(type).data(matcher.remainder()));
return emitInvalid();
}
emitInstruction(maker.alternates());
return true;
case BINDVAR:
{
if (!skipWhitespace()) {
return emitInvalid();
}
// Parse the variable name.
if (!matcher.localVariable()) {
fail(error(BINDVAR_EXPECTS_NAME).data(matcher.remainder()));
return emitInvalid();
}
String name = matcher.consume().repr();
if (!skipWhitespace()) {
return emitInvalid();
}
Variables vars = parseVariables();
if (vars == null) {
fail(error(MISSING_VARIABLE_NAME).data(matcher.remainder()));
return emitInvalid();
}
BindVarInst instruction = maker.bindvar(name, vars);
List<FormatterCall> formatters = parseFormatters(instruction, start);
if (formatters == null) {
emitInstruction(instruction);
} else if (!formatters.isEmpty()) {
instruction.setFormatters(formatters);
emitInstruction(instruction);
}
return true;
}
case CTXVAR:
{
if (!skipWhitespace()) {
return emitInvalid();
}
// Parse the variable name
if (!matcher.localVariable()) {
fail(error(CTXVAR_EXPECTS_NAME).data(matcher.remainder()));
return emitInvalid();
}
String name = matcher.consume().repr();
if (!skipWhitespace()) {
return emitInvalid();
}
List<Binding> bindings = parseBindings();
if (bindings == null) {
fail(error(CTXVAR_EXPECTS_BINDINGS).data(matcher.remainder()));
return emitInvalid();
}
CtxVarInst instruction = maker.ctxvar(name, bindings);
emitInstruction(instruction);
return true;
}
case EVAL:
{
if (!skipWhitespace()) {
return emitInvalid();
}
// Instruction has a single argument, a free-form expression
StringView code = matcher.remainder();
// The expression will be parsed and assembled the first time
// the instruction is executed.
EvalInst instruction = maker.eval(code.toString());
emitInstruction(instruction);
return true;
}
case END:
case META_LEFT:
case META_RIGHT:
case NEWLINE:
case SPACE:
case TAB:
// Nothing should follow these instructions.
if (!matcher.finished()) {
fail(error(EXTRA_CHARS).type(type).data(matcher.remainder()));
return emitInvalid();
}
emitInstruction(maker.simple(type));
return true;
case IF:
return parseIfExpression();
case INCLUDE:
{
// this instruction accepts space-delimited arguments
if (!matcher.space()) {
return emitInvalid();
}
// argument delimiter.
if (!matcher.arguments()) {
return emitInvalid();
}
StringView rawArgs = matcher.consume();
Arguments args = new Arguments(rawArgs);
if (args.count() < 1) {
return emitInvalid();
}
IncludeInst instruction = maker.include(args);
emitInstruction(instruction);
return true;
}
case INJECT:
{
if (!skipWhitespace()) {
return emitInvalid();
}
if (!matcher.localVariable()) {
fail(error(INJECT_EXPECTS_NAME).data(matcher.remainder()));
return emitInvalid();
}
String variable = matcher.consume().repr();
if (!skipWhitespace()) {
return emitInvalid();
}
if (!matcher.path()) {
fail(error(INJECT_EXPECTS_PATH).data(matcher.remainder()));
return emitInvalid();
}
String path = matcher.consume().repr();
StringView rawArgs = null;
Arguments args = Constants.EMPTY_ARGUMENTS;
if (matcher.arguments()) {
rawArgs = matcher.consume();
args = new Arguments(rawArgs);
}
InjectInst instruction = maker.inject(variable, path, args);
emitInstruction(instruction);
return true;
}
case MACRO:
{
if (!skipWhitespace()) {
return emitInvalid();
}
if (!matcher.path()) {
fail(error(MACRO_EXPECTS_NAME));
return emitInvalid();
}
StringView path = matcher.consume();
if (!matcher.finished()) {
fail(error(EXTRA_CHARS).type(type).data(matcher.remainder()));
return emitInvalid();
}
MacroInst inst = maker.macro(path.repr());
emitInstruction(inst);
return true;
}
case OR_PREDICATE:
if (matcher.space()) {
matcher.consume();
if (!matcher.predicate()) {
fail(error(OR_EXPECTED_PREDICATE).type(type).data(matcher.remainder()));
return emitInvalid();
}
Predicate predicate = resolvePredicate(matcher.consume());
Arguments args = parsePredicateArguments(predicate);
if (args == null) {
// Error was emitted by parsePredicateArguments()
return emitInvalid();
}
PredicateInst inst = maker.predicate(predicate, args);
inst.setOr();
emitInstruction(inst);
return true;
}
if (!matcher.finished()) {
fail(error(EXTRA_CHARS).type(type).data(matcher.remainder()));
return emitInvalid();
}
emitInstruction(maker.or());
return true;
case REPEATED:
case SECTION:
return parseSection(type);
default:
throw new RuntimeException("Resolution failure: instruction type '" + type + "' has no text representation.");
}
}
use of com.squarespace.template.Instructions.EvalInst in project template-compiler by Squarespace.
the class TreeEmitter method emitHeader.
private static void emitHeader(InstructionType type, Instruction inst, int depth, StringBuilder buf) {
if (type.equals(InstructionType.ROOT)) {
return;
}
indent(depth, buf);
buf.append(type.toString());
buf.append(" {").append(inst.getLineNumber()).append(',').append(inst.getCharOffset()).append("}");
switch(type) {
case BINDVAR:
BindVarInst bindvar = (BindVarInst) inst;
buf.append(' ').append(bindvar.getName()).append(" = ");
emitVariables(bindvar.getVariables(), buf);
break;
case COMMENT:
CommentInst comment = (CommentInst) inst;
buf.append(' ');
emitEscapedString(comment.getView(), buf);
break;
case EVAL:
EvalInst eval = (EvalInst) inst;
buf.append(' ');
emitEscapedString(eval.body(), buf);
break;
case INCLUDE:
{
IncludeInst include = (IncludeInst) inst;
buf.append(' ');
emitArgs(include.getArguments(), buf);
break;
}
case IF:
{
if (inst instanceof IfInst) {
buf.append(' ');
ReprEmitter.emitIfExpression((IfInst) inst, buf);
} else {
IfPredicateInst predicateInst = (IfPredicateInst) inst;
Predicate predicate = predicateInst.getPredicate();
if (predicate != null) {
buf.append(' ').append(predicate);
Arguments args = predicateInst.getArguments();
if (!args.isEmpty()) {
buf.append(' ');
emitArgs(args, buf);
}
}
}
break;
}
case INJECT:
{
InjectInst inject = (InjectInst) inst;
buf.append(' ');
emitEscapedString(inject.variable(), buf);
buf.append(' ');
emitEscapedString(inject.filename(), buf);
buf.append(' ');
emitArgs(inject.arguments(), buf);
break;
}
case OR_PREDICATE:
case PREDICATE:
PredicateInst predicateInst = (PredicateInst) inst;
Predicate predicate = predicateInst.getPredicate();
if (predicate != null) {
buf.append(' ').append(predicate);
Arguments args = predicateInst.getArguments();
if (!args.isEmpty()) {
buf.append(' ');
emitArgs(args, buf);
}
}
break;
case REPEATED:
RepeatedInst repeated = (RepeatedInst) inst;
buf.append(' ');
emitNames(repeated.getVariable(), buf);
break;
case SECTION:
SectionInst section = (SectionInst) inst;
buf.append(' ');
emitNames(section.getVariable(), buf);
break;
case TEXT:
TextInst text = (TextInst) inst;
buf.append(' ');
emitEscapedString(text.getView(), buf);
break;
case VARIABLE:
{
VariableInst varInst = (VariableInst) inst;
Variables variables = varInst.getVariables();
buf.append(' ');
ReprEmitter.emitVariables(variables, buf);
for (FormatterCall formatterCall : varInst.getFormatters()) {
buf.append('\n');
indent(depth + INCR, buf);
buf.append("| ");
buf.append(formatterCall.getFormatter().identifier());
Arguments args = formatterCall.getArguments();
if (!args.isEmpty()) {
buf.append(' ');
emitArgs(args, buf);
}
}
break;
}
default:
break;
}
buf.append('\n');
}
Aggregations