view parser/Action.d @ 48:b6c1dc30ca4b new_gen

Only tests that dont pass now are structs and switches As far as the parser is concerned assignments are binary expressions Fixed a bug in codegen of if's - it is important to remember that the builder might be positioned at a new block after generating sub-statements
author Anders Halager <halager@gmail.com>
date Thu, 24 Apr 2008 19:42:53 +0200
parents 90fb4fdfefdd
children c7cde6af0095
line wrap: on
line source

module parser.Action;

import lexer.Token;

import ast.Exp,
       ast.Stmt,
       ast.Decl;

import misc.Error;

import tango.io.Stdout,
       Integer = tango.text.convert.Integer;

/**
  Used to indicate what type of operator is used in a given binary expression
  (and unary expressions?)
 */
public enum Operator
{
    Assign,

    Eq, Ne,

    Lt, Le,
    Gt, Ge,

    Add, Sub,
    Mul, Div, Mod,
}


struct Id
{
    Token tok;

    char[] toString()
    {
        return tok.get;
    }
}

/**
  All methods are optional.

Warning: Interface is not stable yet. Use the `override` keyword in all classes
            inheriting from this to get warning if the interface changes.
 */
abstract class Action
{
    /**
      A few aliases to indicate what methods should be dealing with the same
      types.

      Not typesafe, and not using typedef because users would need a lot of
      casts (and base type would be void*, so no possibility to synchronize,
      print etc.)
     */
    alias Object ExprT;
    alias Object StmtT; /// ditto
    alias Object DeclT; /// ditto

    // -- Declarations --

    /**
      Either we should have one case that handles a lot of things, or we should
      have a lot of separate cases.
      As an example, this method could handle the params in `int f(int, int)`
      as well as handling `int x` at both top-level, in classes and in methods.
      
      The other solution is an addParamToFunc or similar.
     */
    DeclT actOnDeclarator(ref Id type, ref Id name, ExprT init)
    {
        return null;
    }

    /**
      Add an initialization expression to a previously created decl.

      Used for default values on function params and for values to local
      variables.
     */
    void addInitToDeclarator(DeclT decl, ExprT exp)
    {
    }

    /**
      Called at the start of a function, doesn't get a lot of info - that is
      added later on, through addFuncArg and actOnEndOfFunction.
     */
    DeclT actOnStartOfFunctionDef(ref Id type, ref Id name)
    {
        return null;
    }

    /**
      Add a new parameter to the function func.
     */
    void addFuncArg(DeclT func, Id type, Id name)
    {
    }

    /**
      Finish off the function, by giving it the body (a single statement, so
      you probably want some sort of compound statement)
     */
    DeclT actOnEndOfFunction(DeclT func, StmtT stmts)
    {
        return func;
    }

    // -- Statements --

    /**
      Called after parsing a function/while/for/whatever body.

      Note that stmts is to be considered temporary, it might point into the
      stack and needs to be copied before saving.
     */
    StmtT actOnCompoundStmt(ref Token left, ref Token right, StmtT[] stmts)
    {
        return null;
    }

    /**
      An expression was used as a statement - this includes assignments,
      function calls.

      Additionally the D spec dictates that expressions with no effect are not
      legal as statements, but the parser can't test for this so it has to be
      done in the later stages.
     */
    StmtT actOnExprStmt(ExprT exp)
    {
        return null;
    }

    /**
      Called after parsing return statements.

      loc is the return token.
     */
    StmtT actOnReturnStmt(ref Token loc, ExprT exp)
    {
        return null;
    }

    /**
     */
    StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody,
                      ref Token elseTok, StmtT elseBody)
    {
        return null;
    }

    /**
     */
    StmtT actOnWhileStmt(ref Token whileTok, ExprT cond, StmtT whileBody)
    {
        return null;
    }

    /**
     */
    StmtT actOnDeclStmt(DeclT decl)
    {
        return null;
    }

    StmtT actOnStartOfSwitchStmt()
    {
        return null;
    }

    void actOnCaseStmt()
    {
    }

    void actOnDefaultStmt()
    {
    }

    StmtT actOnFinishSwitchStmt(StmtT sw)
    {
        return sw;
    }

    // -- Expressions --

    /**
      A single numerical constant -- this can be absolutely any kind of number.
      Integers, floats, hex, octal, binary, imaginary and so on.
     */
    ExprT actOnNumericConstant(Token op)
    {
        return null;
    }

    /**
      This is called when identifiers are used in expressions.
     */
    ExprT actOnIdentifierExp(Id id)
    {
        return null;
    }

    /**
      Unary operator.
     */
    ExprT actOnUnaryOp(Token op, ExprT operand)
    {
        return null;
    }

    /**
      Binary operator.
     */
    ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r)
    {
        return null;
    }

    /**
      Called when using the 'dot' operator.
      The left hand side can be any expression, but its only possible to look
      up an identifier.
     */
    ExprT actOnMemberReference(ExprT lhs, Location op, Id member)
    {
        return null;
    }

    /**
      Called when function calls are encountered.

      Note that args is temporary and might point into the stack. Remember to
      copy before saving a reference to it.
     */
    ExprT actOnCallExpr(ExprT func, ref Token left_paren, ExprT[] args,
                        ref Token right_paren)
    {
        return null;
    }
}

/**
  This class implements the default actions for Dang, by building up an AST
  with the data needed in a compiler.
 */
class AstAction : Action
{
    // -- Declarations --
    override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init)
    {
        Exp exp = cast(Exp)init;
        return new VarDecl(new Identifier(type.tok), new Identifier(id.tok), exp);
    }

    override DeclT actOnStartOfFunctionDef(ref Id type, ref Id name)
    {
        return new FuncDecl(new Identifier(type.tok), new Identifier(name.tok));
    }

    override void addFuncArg(DeclT func, Id type, Id name)
    {
        FuncDecl fd = cast(FuncDecl)func;
        fd.addParam(new Identifier(type.tok), new Identifier(name.tok));
    }

    override DeclT actOnEndOfFunction(DeclT func, StmtT stmts)
    {
        FuncDecl fd = cast(FuncDecl)func;
        fd.setBody(cast(CompoundStatement)stmts);
        return fd;
    }

    // -- Statements --
    override StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts)
    {
        StmtT[] array = stmts.dup;
        Stmt[] statements = cast(Stmt[])array;
        return new CompoundStatement(statements);
    }

    override StmtT actOnExprStmt(ExprT exp)
    {
        return new ExpStmt(cast(Exp)exp);
    }

    override StmtT actOnReturnStmt(ref Token loc, ExprT exp)
    {
        Exp e = cast(Exp)exp;
        auto res = new ReturnStmt;
        res.exp = e;
        return res;
    }

    override StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody,
                               ref Token elseTok, StmtT elseBody)
    {
        Exp c = cast(Exp)cond;
        Stmt t = cast(Stmt)thenBody;
        Stmt e = cast(Stmt)elseBody;
        return new IfStmt(c, t, e);
    }

    override StmtT actOnWhileStmt(ref Token tok, ExprT cond, StmtT whileBody)
    {
        Exp c = cast(Exp)cond;
        Stmt b = cast(Stmt)whileBody;
        return new WhileStmt(c, b);
    }

    override StmtT actOnDeclStmt(DeclT decl)
    {
        Decl d = cast(Decl)decl;
        return new DeclStmt(d);
    }

    // -- Expressions --
    override ExprT actOnNumericConstant(Token c)
    {
        return new IntegerLit(c);
    }

    override ExprT actOnIdentifierExp(Id id)
    {
        return new Identifier(id.tok);
    }

    override ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r)
    {
        Exp left = cast(Exp)l;
        Exp right = cast(Exp)r;
        if (op == Operator.Assign)
            return new AssignExp(left, right);
        else
            return new BinaryExp(cast(BinaryExp.Operator)op, left, right);
    }

    override ExprT actOnUnaryOp(Token op, ExprT operand)
    {
        Exp target = cast(Exp)operand;
        // can only be -x for now
        return new NegateExp(target);
    }

    override ExprT actOnCallExpr(ExprT fn, ref Token, ExprT[] args, ref Token)
    {
        Exp f = cast(Exp)fn;
        Exp[] arguments = cast(Exp[])args.dup;
        return new CallExp(f, arguments);
    }
}