Started working on the AST + parser
This commit is contained in:
parent
126c8358ff
commit
77d46da19a
4 changed files with 390 additions and 2 deletions
1
Makefile
1
Makefile
|
@ -29,6 +29,7 @@ DEMO = \
|
||||||
odbg.cc \
|
odbg.cc \
|
||||||
sync.cc \
|
sync.cc \
|
||||||
control.cc \
|
control.cc \
|
||||||
|
opast.cc \
|
||||||
\
|
\
|
||||||
demo.cc \
|
demo.cc \
|
||||||
\
|
\
|
||||||
|
|
4
demo.srd
4
demo.srd
|
@ -1,4 +1,4 @@
|
||||||
(fn init ()
|
(init
|
||||||
# Compute viewport size
|
# Compute viewport size
|
||||||
(if (gt width height)
|
(if (gt width height)
|
||||||
(
|
(
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
(call dof-init)
|
(call dof-init)
|
||||||
)
|
)
|
||||||
|
|
||||||
(fn frame ()
|
(frame
|
||||||
(profiling "Frame render"
|
(profiling "Frame render"
|
||||||
{ FIXME: other stages }
|
{ FIXME: other stages }
|
||||||
(call dof-main { FIXME: args here })
|
(call dof-main { FIXME: args here })
|
||||||
|
|
217
opast.cc
Normal file
217
opast.cc
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
#include "opast.hh"
|
||||||
|
|
||||||
|
using namespace ebcl;
|
||||||
|
using namespace opast;
|
||||||
|
|
||||||
|
|
||||||
|
/*= A_Node ===================================================================*/
|
||||||
|
|
||||||
|
A_Node::A_Node( const E_Type type ,
|
||||||
|
A_Node* const parent ) noexcept
|
||||||
|
: type_( type ) , parent_( parent )
|
||||||
|
{
|
||||||
|
assert( ( type == ROOT && !parent ) || ( type != ROOT && parent ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
A_Node::~A_Node( ) { }
|
||||||
|
|
||||||
|
T_RootNode& A_Node::root( ) const noexcept
|
||||||
|
{
|
||||||
|
A_Node const* node( this );
|
||||||
|
while ( node->parent_ ) {
|
||||||
|
node = node->parent_;
|
||||||
|
}
|
||||||
|
assert( node );
|
||||||
|
assert( node->type_ == ROOT );
|
||||||
|
return *dynamic_cast< T_RootNode* >(
|
||||||
|
const_cast< A_Node* >( node ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*= A_FuncNode ===============================================================*/
|
||||||
|
|
||||||
|
A_FuncNode::A_FuncNode(
|
||||||
|
const bool isInit ,
|
||||||
|
T_RootNode* const root ) noexcept
|
||||||
|
: A_Node( isInit ? DECL_INIT : DECL_FRAME , root ) ,
|
||||||
|
name_( isInit ? "*init*" : "*frame*" )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
A_FuncNode::A_FuncNode(
|
||||||
|
T_String const& name ,
|
||||||
|
T_RootNode* const root ) noexcept
|
||||||
|
: A_Node( DECL_FN , root ) , name_( name )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_RootNode ===============================================================*/
|
||||||
|
|
||||||
|
T_RootNode::T_RootNode( ) noexcept
|
||||||
|
: A_Node( ROOT , nullptr ) , functions_(
|
||||||
|
[]( T_OwnPtr< A_FuncNode > const& f ) {
|
||||||
|
return f->name( );
|
||||||
|
} )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
T_RootNode::T_AddFunctionResult T_RootNode::addFunction(
|
||||||
|
T_OwnPtr< A_FuncNode >& function ) noexcept
|
||||||
|
{
|
||||||
|
T_String const& fn( function->name( ) );
|
||||||
|
auto const* const pf( functions_.get( fn ) );
|
||||||
|
if ( !pf ) {
|
||||||
|
auto* const rv( function.get( ) );
|
||||||
|
functions_.add( std::move( function ) );
|
||||||
|
return *rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
T_String dfn;
|
||||||
|
uint32_t dupCtr( 0 );
|
||||||
|
do {
|
||||||
|
T_StringBuilder fnsb;
|
||||||
|
fnsb << fn << " dup " << dupCtr ++;
|
||||||
|
dfn = std::move( fnsb );
|
||||||
|
} while ( functions_.contains( dfn ) );
|
||||||
|
|
||||||
|
T_OwnPtr< A_FuncNode > df( NewOwned< T_FuncNode >( dfn , *this ) );
|
||||||
|
auto* const rv( df.get( ) );
|
||||||
|
functions_.add( std::move( df ) );
|
||||||
|
return T_AddFunctionResult{ *rv , (*pf)->location( ) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_SpecialFuncNode ========================================================*/
|
||||||
|
|
||||||
|
T_SpecialFuncNode::T_SpecialFuncNode(
|
||||||
|
bool isInit ,
|
||||||
|
T_RootNode& parent ) noexcept
|
||||||
|
: A_FuncNode( isInit , &parent )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_FuncNode ===============================================================*/
|
||||||
|
|
||||||
|
T_FuncNode::T_FuncNode(
|
||||||
|
T_String const& name ,
|
||||||
|
T_RootNode& parent ) noexcept
|
||||||
|
: A_FuncNode( name , &parent )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
T_Optional< T_SRDLocation > T_FuncNode::addArgument(
|
||||||
|
T_SRDToken const& token ) noexcept
|
||||||
|
{
|
||||||
|
assert( token.type( ) == E_SRDTokenType::WORD );
|
||||||
|
assert( token.hasLocation( ) );
|
||||||
|
|
||||||
|
const auto pnp( argNames_.indexOf( token.stringValue( ) ) );
|
||||||
|
if ( pnp != -1 ) {
|
||||||
|
return argLocations_[ pnp ];
|
||||||
|
}
|
||||||
|
argNames_.add( token.stringValue( ) );
|
||||||
|
argLocations_.add( token.location( ) );
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_Parser =================================================================*/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct T_ParserImpl_
|
||||||
|
{
|
||||||
|
T_OwnPtr< T_RootNode >& root;
|
||||||
|
T_Array< T_SRDError >& errors;
|
||||||
|
|
||||||
|
T_ParserImpl_( T_Array< T_SRDError >* errors ,
|
||||||
|
T_OwnPtr< T_RootNode >* root ) noexcept;
|
||||||
|
|
||||||
|
void parseFunction( T_SRDList const& funcList ) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
T_ParserImpl_::T_ParserImpl_(
|
||||||
|
T_Array< T_SRDError >* const errors ,
|
||||||
|
T_OwnPtr< T_RootNode >* const root ) noexcept
|
||||||
|
: root( *root ) , errors( *errors )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void T_ParserImpl_::parseFunction(
|
||||||
|
T_SRDList const& funcList ) noexcept
|
||||||
|
{
|
||||||
|
assert( funcList.size( ) != 0 );
|
||||||
|
|
||||||
|
auto const& fw( funcList[ 0 ] );
|
||||||
|
if ( fw.type( ) != E_SRDTokenType::WORD
|
||||||
|
|| ( fw.stringValue( ) != "init" && fw.stringValue( ) != "frame"
|
||||||
|
&& fw.stringValue( ) != "fn" ) ) {
|
||||||
|
errors.addNew( "init, frame or fn expected" , fw.location( ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
T_String const& ftw( fw.stringValue( ) );
|
||||||
|
T_OwnPtr< A_FuncNode > fn;
|
||||||
|
if ( ftw == "fn" ) {
|
||||||
|
if ( funcList.size( ) < 3 ) {
|
||||||
|
errors.addNew( "function name and arguments expected" ,
|
||||||
|
fw.location( ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( funcList[ 1 ].type( ) != E_SRDTokenType::WORD ) {
|
||||||
|
errors.addNew( "function name expected" , funcList[ 1 ].location( ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn = NewOwned< T_FuncNode >( funcList[ 1 ].stringValue( ) , *root );
|
||||||
|
// TODO parseFunctionArguments( funcList[ 2 ] );
|
||||||
|
} else {
|
||||||
|
fn = NewOwned< T_SpecialFuncNode >( ftw == "init" , *root );
|
||||||
|
}
|
||||||
|
fn->location( ) = fw.location( );
|
||||||
|
|
||||||
|
const auto af( root->addFunction( fn ) );
|
||||||
|
if ( af.dupLocation.present( ) ) {
|
||||||
|
T_StringBuilder esb( "duplicate " );
|
||||||
|
switch ( fn->type( ) ) {
|
||||||
|
case A_Node::DECL_FN:
|
||||||
|
esb << "function '" << fn->name( ) << "'";
|
||||||
|
break;
|
||||||
|
case A_Node::DECL_INIT:
|
||||||
|
esb << "initialisation function";
|
||||||
|
break;
|
||||||
|
case A_Node::DECL_FRAME:
|
||||||
|
esb << "frame function";
|
||||||
|
break;
|
||||||
|
default: std::abort( );
|
||||||
|
}
|
||||||
|
esb << "; previous declaration: " << *af.dupLocation.target( );
|
||||||
|
errors.addNew( std::move( esb ) , fw.location( ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO parseInstructions( fn->instructions , funcList ,
|
||||||
|
// ftw == "fn" ? 3 : 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
T_Parser::T_Parser( ) noexcept
|
||||||
|
: A_PrivateImplementation( new T_ParserImpl_( &errors_ , &rootNode_ ) ) ,
|
||||||
|
errors_( 64 ) , rootNode_{}
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool T_Parser::parse(
|
||||||
|
T_SRDList const& input ) noexcept
|
||||||
|
{
|
||||||
|
errors_.clear( );
|
||||||
|
rootNode_ = NewOwned< T_RootNode >( );
|
||||||
|
|
||||||
|
for ( auto const& t : input ) {
|
||||||
|
if ( t.type( ) == E_SRDTokenType::LIST && t.list( ).size( ) > 0 ) {
|
||||||
|
p< T_ParserImpl_ >( ).parseFunction( t.list( ) );
|
||||||
|
} else {
|
||||||
|
errors_.addNew( "Function or special block expected" ,
|
||||||
|
t.location( ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors_.empty( );
|
||||||
|
}
|
170
opast.hh
Normal file
170
opast.hh
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
#pragma once
|
||||||
|
//#ifndef REAL_BUILD
|
||||||
|
# include "externals.hh"
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#include <ebcl/SRDData.hh>
|
||||||
|
|
||||||
|
|
||||||
|
namespace opast {
|
||||||
|
|
||||||
|
using namespace ebcl;
|
||||||
|
|
||||||
|
class T_RootNode;
|
||||||
|
|
||||||
|
class A_Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum E_Type {
|
||||||
|
ROOT ,
|
||||||
|
//
|
||||||
|
DECL_INIT ,
|
||||||
|
DECL_FRAME ,
|
||||||
|
DECL_FN ,
|
||||||
|
//
|
||||||
|
OP_SET ,
|
||||||
|
//
|
||||||
|
EXPR_ADD ,
|
||||||
|
EXPR_MUL ,
|
||||||
|
EXPR_SUB ,
|
||||||
|
EXPR_DIV ,
|
||||||
|
EXPR_VAR ,
|
||||||
|
EXPR_CONST ,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
const E_Type type_;
|
||||||
|
A_Node* const parent_;
|
||||||
|
T_SRDLocation location_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit A_Node( const E_Type type ,
|
||||||
|
A_Node* const parent ) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~A_Node( ) = 0;
|
||||||
|
|
||||||
|
E_Type type( ) const noexcept
|
||||||
|
{ return type_; }
|
||||||
|
|
||||||
|
T_SRDLocation& location( ) noexcept
|
||||||
|
{ return location_; }
|
||||||
|
T_SRDLocation const& location( ) const noexcept
|
||||||
|
{ return location_; }
|
||||||
|
|
||||||
|
A_Node& parent( ) const noexcept
|
||||||
|
{ assert( parent_ ); return *parent_; }
|
||||||
|
|
||||||
|
T_RootNode& root( ) const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// Function-like nodes
|
||||||
|
class A_FuncNode : public A_Node
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T_String name_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// For init or frame entry points.
|
||||||
|
// isInit = true => init entry point
|
||||||
|
// isInit = false => frame entry point
|
||||||
|
explicit A_FuncNode( bool isInit ,
|
||||||
|
T_RootNode* const parent ) noexcept;
|
||||||
|
|
||||||
|
// For normal functions
|
||||||
|
explicit A_FuncNode( T_String const& name ,
|
||||||
|
T_RootNode* const parent ) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
T_String const& name( ) const noexcept
|
||||||
|
{ return name_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Root node, keeps track of the whole tree and related data (function table,
|
||||||
|
// assets...)
|
||||||
|
class T_RootNode : public A_Node
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T_ObjectTable< T_String , T_OwnPtr< A_FuncNode > > functions_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
T_RootNode( ) noexcept;
|
||||||
|
|
||||||
|
// Return type for addFunction. We'll always return a reference to a
|
||||||
|
// function node (which may or may not be the same as the initial one,
|
||||||
|
// if there were duplicates), and we'll return the location of the
|
||||||
|
// initial function in the case of a duplicate.
|
||||||
|
struct T_AddFunctionResult
|
||||||
|
{
|
||||||
|
A_FuncNode& function;
|
||||||
|
T_Optional< T_SRDLocation > dupLocation;
|
||||||
|
|
||||||
|
T_AddFunctionResult( A_FuncNode& function ) noexcept
|
||||||
|
: function{ function } , dupLocation{}
|
||||||
|
{}
|
||||||
|
|
||||||
|
T_AddFunctionResult( A_FuncNode& function ,
|
||||||
|
T_SRDLocation const& dupLocation ) noexcept
|
||||||
|
: function{ function } , dupLocation{ dupLocation }
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attempts to add a function. If the function is already present in
|
||||||
|
// the table, the result will be set up with the previous declaration's
|
||||||
|
// location, and the specified function will not be modified (a duplicate
|
||||||
|
// entry will be added to the table instead).
|
||||||
|
T_AddFunctionResult addFunction(
|
||||||
|
T_OwnPtr< A_FuncNode >& function ) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// Init & frame functions
|
||||||
|
class T_SpecialFuncNode : public A_FuncNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
T_SpecialFuncNode(
|
||||||
|
bool isInit ,
|
||||||
|
T_RootNode& parent ) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Normal functions
|
||||||
|
class T_FuncNode : public A_FuncNode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T_AutoArray< T_String , 8 > argNames_;
|
||||||
|
T_AutoArray< T_SRDLocation , 8 > argLocations_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
T_FuncNode( T_String const& name ,
|
||||||
|
T_RootNode& parent ) noexcept;
|
||||||
|
|
||||||
|
// Add an argument. If the argument is a duplicate, return the location
|
||||||
|
// of the initial argument.
|
||||||
|
T_Optional< T_SRDLocation > addArgument(
|
||||||
|
T_SRDToken const& token ) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class T_Parser : public A_PrivateImplementation
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T_Array< T_SRDError > errors_;
|
||||||
|
T_OwnPtr< T_RootNode > rootNode_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
T_Parser( ) noexcept;
|
||||||
|
|
||||||
|
bool parse( T_SRDList const& input ) noexcept;
|
||||||
|
|
||||||
|
T_Array< T_SRDError > const& errors( ) const noexcept
|
||||||
|
{ return errors_; }
|
||||||
|
T_OwnPtr< T_RootNode > result( ) noexcept
|
||||||
|
{ return std::move( rootNode_ ); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace opast
|
Loading…
Reference in a new issue