Package loop.lisp

Source Code of loop.lisp.SexprParser

package loop.lisp;

import loop.AnnotatedError;
import loop.Parser;
import loop.Token;
import loop.ast.BooleanLiteral;
import loop.ast.ClassDecl;
import loop.ast.InlineListDef;
import loop.ast.IntLiteral;
import loop.ast.LongLiteral;
import loop.ast.Node;
import loop.ast.RegexLiteral;
import loop.ast.StringLiteral;
import loop.ast.Variable;
import loop.ast.script.FunctionDecl;
import loop.ast.script.ModuleDecl;
import loop.ast.script.Unit;

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

/**
* @author dhanji@gmail.com (Dhanji R. Prasanna)
*/
public class SexprParser implements Parser {
  private final List<Token> tokens;
  private int i;

  public SexprParser(List<Token> tokens) {
    this.tokens = tokens;
  }

  /**
   * Parses an S-expression.
   * <p/>
   * sexpr := atom | (LPAREN sexpr* RPAREN)
   */
  @Override
  public Node parse() {
    InlineListDef list = new InlineListDef(false);
    while (!endOfInput()) {
      Node sexpr = sexpr();
      if (sexpr != null)
        list.add(new SexprAstTransformer(sexpr).transform());
    }
    return list;
  }

  private Node sexpr() {
    Node atom = atom();
    if (atom != null)
      return atom;

    List<Token> startParen = match(Token.Kind.LPAREN);
    if (startParen == null)
      return null;

    InlineListDef listDef = new InlineListDef(false).sourceLocation(startParen);
    Node inner;
    while ((inner = sexpr()) != null) {
      listDef.add(inner);
    }

    if (match(Token.Kind.RPAREN) == null)
      throw new RuntimeException("Expected ')'");

    return listDef;
  }

  /**
   * atom := symbol
   */
  private Node atom() {
    Token token = tokens.get(i);

    if (token.kind == Token.Kind.LPAREN || token.kind == Token.Kind.RPAREN)
      return null;

    i++;

    switch (token.kind) {
      case INTEGER:
        return new IntLiteral(token.value);
      case LONG:
        return new LongLiteral(token.value);
      case STRING:
        return new StringLiteral(token.value);
      case REGEX:
        return new RegexLiteral(token.value);
    }

    if ("#t".equals(token.value) || "#true".equals(token.value))
      return new BooleanLiteral(new Token(token.value, Token.Kind.TRUE, token.line, token.column));
    else if ("#f".equals(token.value) || "#false".equals(token.value))
      return new BooleanLiteral(new Token(token.value, Token.Kind.FALSE, token.line, token.column));

    if (token.value.trim().isEmpty())
      return null;

    return new Variable(token.value);
  }

  @Override
  public Unit script(String file) {
    Unit unit = new Unit(file, ModuleDecl.DEFAULT);
    Node parse = parse();
    for (Node child : parse.children()) {
      if (child instanceof FunctionDecl)
        unit.declare((FunctionDecl) child);
      else
        unit.addToInitializer(child);
    }

    return unit;
  }

  @Override
  public List<AnnotatedError> getErrors() {
    return new ArrayList<AnnotatedError>();
  }

  @Override
  public Node line() {
    return null;
  }

  @Override
  public FunctionDecl functionDecl() {
    return null;
  }

  @Override
  public ClassDecl classDecl() {
    throw new UnsupportedOperationException("The S-expression parser does not support classes");
  }

  private List<Token> match(Token.Kind... ident) {
    return match(false, ident);
  }

  private List<Token> matchNot(Token.Kind... ident) {
    return match(true, ident);
  }

  private List<Token> match(boolean not, Token.Kind... ident) {
    int cursor = i;
    for (Token.Kind kind : ident) {

      // What we want is more than the size of the token stream.
      if (cursor >= tokens.size()) {
        return null;
      }

      Token token = tokens.get(cursor);
      if (not) {
        if (token.kind == kind)
          return null;
      } else if (token.kind != kind) {
        return null;
      }

      cursor++;
    }

    // Forward cursor in token stream to match point.
    int start = i;
    i = cursor;
    return tokens.subList(start, i);
  }

  private boolean endOfInput() {
    return i == tokens.size();
  }
}
TOP

Related Classes of loop.lisp.SexprParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.