2024-06-25 18:59:15 +02:00
/// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// AUTOGENERATED COPYRIGHT HEADER END
2024-06-06 13:37:13 +02:00
# include "parser.hpp"
2025-01-25 16:27:50 +01:00
# include <algorithm>
# include <cctype>
# include <cstdarg>
# include "error.hpp"
2024-06-06 13:37:13 +02:00
2025-01-25 16:27:50 +01:00
blitz : : parser : : ~ parser ( ) { }
2024-06-06 13:37:13 +02:00
2025-01-25 16:27:50 +01:00
blitz : : parser : : parser ( std : : filesystem : : path file ) : _file ( file ) , _lexer ( ) , _expr ( )
{
_lexer = std : : make_shared < blitz : : lexer > ( file ) ;
2024-06-06 13:37:13 +02:00
}
2025-01-25 16:27:50 +01:00
std : : shared_ptr < blitz : : ast : : node > blitz : : parser : : current ( )
{
return _expr ;
2024-06-06 13:37:13 +02:00
}
2025-01-25 16:27:50 +01:00
std : : shared_ptr < blitz : : ast : : node > blitz : : parser : : next ( )
{
// This should return an entire "line" of expressions in one go, i.e.:
// 1. Local a = 1, b = a, c = b+a
// -> Local(Variable(a, Expression(Integer(1))), Variable(b, Expresssion(Variable(a))), Variable(c, Expression(Add(Variable(b), Variable(a)))
// 2. Include "HelloWorld.bb"
// -> Include(String("HelloWorld.bb"))
// 3. Function HelloWorld()
// -> Function(HelloWorld, ...)(
// Not quite sure if the above makes sense, we'd be returning many expressions outside of functions, but only one inside a function? Why even bother with the current/next crap then?
// Handling Include becomes a problem too. I guess we should actually return expressions on a line by line basis, and let the "compiler" figure out scope and stuff.
// Grab the next token to figure out what behavior we should have.
2024-06-06 13:37:13 +02:00
while ( true ) {
2025-01-25 16:27:50 +01:00
auto token = _lexer - > next ( ) ;
try {
switch ( token . type ) {
case blitz : : token : : variant : : ENDOFFILE :
// End of file means there's nothing left to parse.
_expr . reset ( ) ;
2024-06-06 13:37:13 +02:00
return nullptr ;
2025-01-25 16:27:50 +01:00
case blitz : : token : : variant : : COMMENT :
case blitz : : token : : variant : : NEWLINE :
case blitz : : token : : variant : : SEPARATOR :
// Ignore some things that aren't very useful right now.
continue ;
case blitz : : token : : variant : : TEXT :
return try_parse ( token ) ;
default :
throw nullptr ;
}
} catch ( blitz : : error const & ex ) {
throw ex ;
} catch ( std : : exception const & ex ) {
throw new blitz : : error ( _file , token . location , token . location , ex . what ( ) ) ;
} catch ( . . . ) {
throw new blitz : : error ( _file , token . location , token . location , blitz : : format ( " Token %s unexpected at this point. " , token . to_string ( ) . c_str ( ) ) ) ;
2024-06-06 13:37:13 +02:00
}
}
}
2025-01-25 16:27:50 +01:00
std : : shared_ptr < blitz : : ast : : node > blitz : : parser : : try_parse ( blitz : : token token )
{
// ToDo: Switch to a proper Unicode library. Maybe Boost?
std : : string ltext ;
std : : transform ( token . text . begin ( ) , token . text . end ( ) , ltext . begin ( ) , [ ] ( std : : string : : value_type c ) { return std : : tolower ( c ) ; } ) ;
if ( ( ltext = = " local " ) | | ( ltext = = " global " ) ) {
// Local/Global have the same parsing, but different functionality.
// Should be:
// Text Text [Symbol(=) Expression] [Symbol(,) Text [Symbol(=) Expression] [Symbol(,) ...]]
} else if ( ltext = = " global " ) {
// Global ...
} else if ( ltext = = " function " ) {
} else if ( ltext = = " select " ) {
} else if ( ltext = = " case " ) {
} else if ( ltext = = " endselect " ) {
} else if ( ltext = = " if " ) {
} else if ( ltext = = " elif " ) {
} else if ( ltext = = " endif " ) {
} else if ( ltext = = " end " ) {
2024-06-06 13:37:13 +02:00
}
2025-01-25 16:27:50 +01:00
return nullptr ;
2024-06-06 13:37:13 +02:00
}
2025-01-25 16:27:50 +01:00
std : : shared_ptr < blitz : : ast : : node > blitz : : parser : : try_parse_variable ( )
{
// Text [Symbol(=) Expression(...)] [Symbol(,) [Text [Symbol(=) Expression(...)]]]
auto label = _lexer - > next ( ) ;
if ( label ! = blitz : : token : : variant : : TEXT ) {
throw new blitz : : error ( _file , label . location , label . location , blitz : : format ( " Unexpected %s, expected Text. " , label . to_string ( ) . c_str ( ) ) ) ;
2024-06-06 13:37:13 +02:00
}
2025-01-25 16:27:50 +01:00
auto node = std : : make_shared < blitz : : ast : : variable > ( label ) ;
auto operand = _lexer - > next ( ) ;
if ( operand = = " = " ) {
//node->set_value(try_parse_expression());
} else if ( operand = = blitz : : token : : variant : : NEWLINE | | operand = = blitz : : token : : variant : : SEPARATOR | | ( operand = = blitz : : token : : variant : : SYMBOL & & operand = = " , " ) ) {
return node ;
} else {
throw new blitz : : error ( _file , label . location , operand . location , blitz : : format ( " Unexpected %s, expected Symbol(=), NewLine, Separator, or Symbol(,). " , operand . to_string ( ) . c_str ( ) ) ) ;
2024-06-06 13:37:13 +02:00
}
2025-01-25 16:27:50 +01:00
return node ;
2024-06-06 13:37:13 +02:00
}