All Downloads are FREE. Search and download functionalities are using the official Maven repository.

space.yizhu.record.template.stat.Parser Maven / Gradle / Ivy

There is a newer version: 1.3.2
Show newest version


package space.yizhu.record.template.stat;

import java.util.ArrayList;
import java.util.List;

import space.yizhu.record.template.Directive;
import space.yizhu.record.template.Env;
import space.yizhu.record.template.expr.ExprParser;
import space.yizhu.record.template.expr.ast.ExprList;
import space.yizhu.record.template.expr.ast.ForCtrl;
import space.yizhu.record.template.stat.ast.*;
import space.yizhu.record.template.stat.ast.*;


public class Parser {

    private static final Token EOF = new Token(Symbol.EOF, -1);

    private int forward = 0;
    private List tokenList;
    private StringBuilder content;
    private String fileName;
    private Env env;

    public Parser(Env env, StringBuilder content, String fileName) {
        this.env = env;
        this.content = content;
        this.fileName = fileName;
    }

    private Token peek() {
        return tokenList.get(forward);
    }

    private Token move() {
        return tokenList.get(++forward);
    }

    private Token matchPara(Token name) {
        Token current = peek();
        if (current.symbol == Symbol.PARA) {
            move();
            return current;
        }
        throw new ParseException("Can not match the parameter of directive #" + name.value(), getLocation(name.row));
    }

    private void matchEnd(Token name) {
        if (peek().symbol == Symbol.END) {
            move();
            return;
        }
        throw new ParseException("Can not match the #end of directive #" + name.value(), getLocation(name.row));
    }

    public StatList parse() {
        tokenList = new Lexer(content, fileName).scan();
        tokenList.add(EOF);
        StatList statList = statList();
        if (peek() != EOF) {
            throw new ParseException("Syntax error: can not match \"#" + peek().value() + "\"", getLocation(peek().row));
        }
        return statList;
    }

    private StatList statList() {
        List statList = new ArrayList();
        while (true) {
            Stat stat = stat();
            if (stat == null) {
                break;
            }

            if (stat instanceof Define) {
                env.addFunction((Define) stat);
                continue;
            }

            
            if (stat instanceof Text && ((Text) stat).isEmpty()) {
                continue;
            }

            statList.add(stat);
        }
        return new StatList(statList);
    }

    private Stat stat() {
        Token name = peek();
        switch (name.symbol) {
            case TEXT:
                move();
                return new Text(((TextToken) name).getContent(), env.getEngineConfig().getEncoding()).setLocation(getLocation(name.row));
            case OUTPUT:
                move();
                Token para = matchPara(name);
                Location loc = getLocation(name.row);
                return env.getEngineConfig().getOutputDirective(parseExprList(para), loc).setLocation(loc);
            case INCLUDE:
                move();
                para = matchPara(name);
                return new Include(env, parseExprList(para), fileName, getLocation(name.row));
            case FOR:
                move();
                para = matchPara(name);
                StatList statList = statList();
                Stat _else = null;
                if (peek().symbol == Symbol.ELSE) {
                    move();
                    StatList elseStats = statList();
                    _else = new Else(elseStats);
                }
                matchEnd(name);
                return new For(parseForCtrl(para), statList, _else).setLocation(getLocation(name.row));
            case IF:
                move();
                para = matchPara(name);
                statList = statList();
                Stat ret = new If(parseExprList(para), statList, getLocation(name.row));

                Stat current = ret;
                for (Token elseIfToken = peek(); elseIfToken.symbol == Symbol.ELSEIF; elseIfToken = peek()) {
                    move();
                    para = matchPara(elseIfToken);
                    statList = statList();
                    Stat elseIf = new ElseIf(parseExprList(para), statList, getLocation(elseIfToken.row));
                    current.setStat(elseIf);
                    current = elseIf;
                }
                if (peek().symbol == Symbol.ELSE) {
                    move();
                    statList = statList();
                    _else = new Else(statList);
                    current.setStat(_else);
                }
                matchEnd(name);
                return ret;
            case DEFINE:
                String functionName = name.value();
                move();
                para = matchPara(name);
                statList = statList();
                matchEnd(name);
                return new Define(functionName, parseExprList(para), statList, getLocation(name.row));
            case CALL:
                functionName = name.value();
                move();
                para = matchPara(name);
                return new Call(functionName, parseExprList(para), false).setLocation(getLocation(name.row));
            case CALL_IF_DEFINED:
                functionName = name.value();
                move();
                para = matchPara(name);
                return new Call(functionName, parseExprList(para), true).setLocation(getLocation(name.row));
            case SET:
                move();
                para = matchPara(name);
                return new Set(parseExprList(para), getLocation(name.row));
            case SET_LOCAL:
                move();
                para = matchPara(name);
                return new SetLocal(parseExprList(para), getLocation(name.row));
            case SET_GLOBAL:
                move();
                para = matchPara(name);
                return new SetGlobal(parseExprList(para), getLocation(name.row));
            case CONTINUE:
                move();
                return Continue.me;
            case BREAK:
                move();
                return Break.me;
            case RETURN:
                move();
                return Return.me;
            case ID:
                Class dire = env.getEngineConfig().getDirective(name.value());
                if (dire == null) {
                    throw new ParseException("Directive not found: #" + name.value(), getLocation(name.row));
                }
                ret = createDirective(dire, name).setLocation(getLocation(name.row));
                move();
                para = matchPara(name);
                ret.setExprList(parseExprList(para));

                if (ret.hasEnd()) {
                    statList = statList();
                    ret.setStat(statList.getActualStat());
                    matchEnd(name);
                }
                return ret;
            case PARA:
            case ELSEIF:
            case ELSE:
            case END:
            case EOF:
            case CASE:
            case DEFAULT:
                return null;
            case SWITCH:
                move();
                para = matchPara(name);
                Switch _switch = new Switch(parseExprList(para), getLocation(name.row));

                CaseSetter currentCaseSetter = _switch;
                for (Token currentToken = peek(); ; currentToken = peek()) {
                    if (currentToken.symbol == Symbol.CASE) {
                        move();
                        para = matchPara(currentToken);
                        statList = statList();
                        Case nextCase = new Case(parseExprList(para), statList, getLocation(currentToken.row));
                        currentCaseSetter.setNextCase(nextCase);
                        currentCaseSetter = nextCase;
                    } else if (currentToken.symbol == Symbol.DEFAULT) {
                        move();
                        statList = statList();
                        Default _default = new Default(statList);
                        _switch.setDefault(_default, getLocation(currentToken.row));
                    } else if (currentToken.symbol == Symbol.TEXT) {
                        TextToken tt = (TextToken) currentToken;
                        if (tt.getContent().toString().trim().length() != 0) {
                            throw new ParseException("Syntax error: expect #case or #default directive", getLocation(currentToken.row));
                        }
                        move();
                    } else {
                        break;
                    }
                }

                matchEnd(name);
                return _switch;
            default:
                throw new ParseException("Syntax error: can not match the token: " + name.value(), getLocation(name.row));
        }
    }

    private Location getLocation(int row) {
        return new Location(fileName, row);
    }

    private Stat createDirective(Class dire, Token name) {
        try {
            return dire.newInstance();
        } catch (Exception e) {
            throw new ParseException(e.getMessage(), getLocation(name.row), e);
        }
    }

    private ExprList parseExprList(Token paraToken) {
        return new ExprParser((ParaToken) paraToken, env.getEngineConfig(), fileName).parseExprList();
    }

    private ForCtrl parseForCtrl(Token paraToken) {
        return new ExprParser((ParaToken) paraToken, env.getEngineConfig(), fileName).parseForCtrl();
    }
}








© 2015 - 2025 Weber Informatics LLC | Privacy Policy