package sicel.compiler.parser.internal;
import java.io.File;
import java.io.IOException;
import sicel.compiler.parser.ASTNode;
import sicel.compiler.parser.Parser;
import sicel.compiler.parser.Token;
import sicel.compiler.parser.exceptions.SyntaxError;
import sicel.compiler.parser.exceptions.UnexpectedTokenError;
import sicel.compiler.parser.internal.ast.*;
import sicel.compiler.parser.internal.tokens.*;
public class ParserImpl extends AbstractParser implements Parser
{
public static void main( String[] args ) throws IOException
{
Parser parser = new ParserImpl();
parser.setLexer( new LexerImpl() );
ASTNode rootNode;
try
{
rootNode = parser.parse( new File( "input.txt" ) );
}
catch ( SyntaxError e )
{
e.printStackTrace();
return;
}
rootNode.printTree();
}
@Override
public final ASTNode parse( File file )
{
lexer.initialize( file );
ASTNode n = new Program();
while( true )
{
while( consumeIf( T_EOL.class ) );
if( lexer.peek() == null )
{
// no more tokens. EOF
break;
}
if( ! binding() )
{
Token t = lexer.take();
throw new UnexpectedTokenError( t, "binding" );
}
n.putChild( consumedNode );
}
return n;
}
private final boolean binding()
{
if( ! consumeIf( T_BINDING.class ) ) return false;
T_BINDING t = (T_BINDING)consumedToken;
ASTNode n = new Binding( t.text );
expression();
n.putChild( consumedNode );
if( lexer.peek() != null )
{
expect( T_EOL.class );
if( consumeIf( T_BRACE_OPEN.class) )
{
while( consumeIf( T_EOL.class ) );
while( binding() )
{
n.putChild( consumedNode );
while( consumeIf( T_EOL.class ) );
}
expect( T_BRACE_CLOSE.class );
}
}
consumedNode = n;
return true;
}
private final boolean binOp( ASTNode lhn )
{
if( lookAhead( 0, T_OPERATOR.class ) )
{
T_OPERATOR op_token = (T_OPERATOR)lexer.take();
Operator op = new Operator( op_token.text );
op.putChild( lhn ); //left-hand node
if( ! unit() )
{
Token t = lexer.take();
throw new UnexpectedTokenError( t );
}
op.putChild( consumedNode ); //right-hand node
if( ! binOp( op ) )
{
consumedNode = op;
}
return true;
}
if( lookAhead( 0, T_INFIX_WORD.class ) )
{
T_INFIX_WORD op_token = (T_INFIX_WORD)lexer.take();
FunctionCall op = new FunctionCall( op_token.text );
op.putChild( lhn ); //left-hand node
if( ! unit() )
{
Token t = lexer.take();
throw new UnexpectedTokenError( t );
}
op.putChild( consumedNode ); //right-hand node
if( ! binOp( op ) )
{
consumedNode = op;
}
return true;
}
return false;
}
private final boolean unit()
{
if( ! ( literalList() || lambda() || functionCall() || parenGroup() || atom() ) )
{
return false;
}
dotCall( consumedNode );
return true;
}
private final boolean dotCall( ASTNode lhs )
{
if( ! consumeIf( T_DOT.class ) ) return false;
if( ! functionCall() )
{
Token t = lexer.take();
throw new UnexpectedTokenError( t, "function call" );
}
consumedNode.putChild( 0, lhs );
dotCall( consumedNode );
return true;
}
private final boolean expression()
{
if( ! unit() ) return false;
binOp( consumedNode );
return true;
}
private final boolean lambda()
{
if( ! lookAhead( 1, T_ARROW.class ) ) return false;
T_WORD word = (T_WORD)expect( T_WORD.class );
ASTNode lambda = new Lambda( word.text );
lexer.take(); // arrow
if( ! expression() )
{
Token t = lexer.take();
throw new UnexpectedTokenError( t, "expression" );
}
lambda.putChild( consumedNode );
consumedNode = lambda;
return true;
}
private final boolean functionCall()
{
if( ! consumeIf( T_WORD.class ) ) return false;
T_WORD word = (T_WORD)consumedToken;
ASTNode fc = new FunctionCall( word.text );
if( consumeIf( T_PAREN_OPEN.class ) )
{
if( expression() )
{
fc.putChild( consumedNode );
while( consumeIf( T_COMMA.class ) )
{
if( ! expression() )
{
Token t = lexer.take();
throw new SyntaxError( "Expected expression", "", t.getLine(), t.getColumn() );
}
fc.putChild( consumedNode );
}
}
if( ! consumeIf( T_PAREN_CLOSE.class ) )
{
Token t = lexer.take();
throw new UnexpectedTokenError( t, T_PAREN_CLOSE.class );
}
}
consumedNode = fc;
return true;
}
private final boolean atom()
{
if( consumeIf( T_INT_LITERAL.class ) )
{
consumedNode = new IntLiteral( ( (T_INT_LITERAL)consumedToken ).value );
return true;
}
if( consumeIf( T_DOUBLE_LITERAL.class ) )
{
consumedNode = new DoubleLiteral( ( (T_DOUBLE_LITERAL)consumedToken ).value );
return true;
}
if( consumeIf( T_STRING_LITERAL.class ) )
{
consumedNode = new StringLiteral( ( (T_STRING_LITERAL)consumedToken ).value );
return true;
}
return false;
}
private final boolean literalList()
{
if( ! consumeIf( T_SQUARE_OPEN.class ) ) return false;
ASTNode n = new LiteralList();
if( expression() )
{
n.putChild( consumedNode );
while( consumeIf( T_COMMA.class ) )
{
if( ! expression() )
{
Token t = lexer.take();
throw new UnexpectedTokenError( t, "expression" );
}
n.putChild( consumedNode );
}
}
consumedNode = n;
expect( T_SQUARE_CLOSE.class );
return true;
}
private final boolean parenGroup()
{
if( ! consumeIf( T_PAREN_OPEN.class ) ) return false;
expression();
expect( T_PAREN_CLOSE.class );
return true;
}
}