From 36d255c66cb2d16f398a38fcf45056e9d0bcb15c Mon Sep 17 00:00:00 2001 From: fakelag <35497506+fakelag@users.noreply.github.com> Date: Sun, 14 Jun 2020 12:27:53 +0300 Subject: [PATCH 1/3] Complex types (WIP) --- Includes/QScript.h | 6 +- Library/Common/Object.h | 10 +- Library/Compiler/AST/AST.cpp | 74 ++++++------ Library/Compiler/AST/AST.h | 38 +----- Library/Compiler/AST/Typing.cpp | 201 ++++++++++++++++++++----------- Library/Compiler/AST/Typing.h | 64 ++++++++++ Library/Compiler/Compiler.cpp | 39 +++--- Library/Compiler/Compiler.h | 24 ++-- Library/Compiler/IRGenerator.cpp | 7 +- 9 files changed, 283 insertions(+), 180 deletions(-) create mode 100644 Library/Compiler/AST/Typing.h diff --git a/Includes/QScript.h b/Includes/QScript.h index b9e5b7a..edf9a49 100644 --- a/Includes/QScript.h +++ b/Includes/QScript.h @@ -10,6 +10,8 @@ #endif #endif +#include "Typing.h" + struct VM_t; namespace Compiler @@ -17,8 +19,8 @@ namespace Compiler class BaseNode; struct Variable_t; - std::string TypeToString( uint32_t type ); - bool TypeCheck( uint32_t targetType, uint32_t exprType, bool strict = true ); + std::string TypeToString( Type_t type ); + bool TypeCheck( Type_t targetType, Type_t exprType ); } namespace QScript diff --git a/Library/Common/Object.h b/Library/Common/Object.h index fd6df49..0f8258c 100644 --- a/Library/Common/Object.h +++ b/Library/Common/Object.h @@ -1,5 +1,6 @@ #pragma once #include "Value.h" +#include "Typing.h" namespace QScript { @@ -25,9 +26,8 @@ namespace QScript public: struct Arg_t { - std::string m_Name; - uint32_t m_Type; - uint32_t m_RetType; + std::string m_Name; + Compiler::Type_t m_Type; }; FORCEINLINE FunctionObject( const std::string& name, Chunk_t* chunk ) @@ -46,9 +46,9 @@ namespace QScript FORCEINLINE const std::vector< Arg_t >& GetArgs() const { return m_Arguments; } FORCEINLINE void SetUpvalues( int numUpvalues ) { ++m_NumUpvalues; } - FORCEINLINE void AddArgument( const std::string& name, uint32_t type, uint32_t retType ) + FORCEINLINE void AddArgument( const std::string& name, Compiler::Type_t type ) { - m_Arguments.push_back( Arg_t{ name, type, retType } ); + m_Arguments.push_back( Arg_t{ name, type } ); } private: diff --git a/Library/Compiler/AST/AST.cpp b/Library/Compiler/AST/AST.cpp index ad1ba96..6cc48a1 100644 --- a/Library/Compiler/AST/AST.cpp +++ b/Library/Compiler/AST/AST.cpp @@ -1,5 +1,6 @@ #include "QLibPCH.h" #include "Instructions.h" +#include "Typing.h" #include "../../Common/Chunk.h" #include "../../STL/NativeModule.h" @@ -198,7 +199,7 @@ namespace Compiler return argsList; } - QScript::FunctionObject* CompileFunction( bool isAnonymous, bool isConst, bool isMember, const std::string& name, ListNode* funcNode, Assembler& assembler, uint32_t* outReturnType = NULL ) + QScript::FunctionObject* CompileFunction( bool isAnonymous, bool isConst, bool isMember, const std::string& name, ListNode* funcNode, Assembler& assembler, Type_t* outReturnType = NULL ) { auto chunk = assembler.CurrentChunk(); auto& nodeList = funcNode->GetList(); @@ -220,8 +221,8 @@ namespace Compiler // Create args in scope auto argsList = ParseArgsList( argNode ); std::for_each( argsList.begin(), argsList.end(), [ &assembler, &function ]( const Argument_t& item ) { - function->AddArgument( item.m_Name, item.m_Type, TYPE_UNKNOWN ); // TODO: Return type support - assembler.AddLocal( item.m_Name, true, item.m_LineNr, item.m_ColNr, item.m_Type, TYPE_UNKNOWN ); + function->AddArgument( item.m_Name, item.m_Type ); + assembler.AddLocal( item.m_Name, true, item.m_LineNr, item.m_ColNr, item.m_Type ); } ); // Compile function body @@ -277,12 +278,13 @@ namespace Compiler case NODE_RETURN: { // Check that the function can return null - uint32_t retnType = assembler.CurrentContext()->m_ReturnType; + auto& type = assembler.CurrentContext()->m_Type; + auto retnType = type.m_ReturnType ? *type.m_ReturnType : Type_t( TYPE_UNKNOWN ); - if ( retnType != TYPE_UNKNOWN && !( retnType & TYPE_NULL ) ) + if ( !retnType.IsUnknown() && !( retnType & TYPE_NULL ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( retnType ) + ", got: " + TypeToString( TYPE_NULL ), + TypeToString( retnType.m_Bits ) + ", got: " + TypeToString( TYPE_NULL ), LineNr(), ColNr(), Token() ); } @@ -569,7 +571,8 @@ namespace Compiler auto leftType = m_Left->ExprType( assembler ); auto rightType = m_Right->ExprType( assembler ); - if ( !TypeCheck( leftType, rightType, false ) ) + + if ( !( leftType & TYPE_NULL ) && !TypeCheck( leftType, rightType ) ) { throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + TypeToString( rightType ) + " to variable of type " + TypeToString( leftType ), @@ -602,26 +605,26 @@ namespace Compiler auto leftString = !!( leftType & TYPE_STRING ); auto rightString = !!( rightType & TYPE_STRING ); - if ( !TypeCheck( leftType, TYPE_NUMBER ) && !leftString ) + if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) && !leftString ) { throw CompilerException( "cp_invalid_expression_type", "Expected variable of type " + - TypeToString( TYPE_NUMBER | TYPE_STRING ) + ", got: " + TypeToString( leftType ), + TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - if ( !TypeCheck( rightType, TYPE_NUMBER ) && !rightString ) + if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) && !rightString ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( TYPE_NUMBER | TYPE_STRING ) + ", got: " + TypeToString( rightType ), + TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( rightType ), m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); } // If the variable is a num, but right hand operand is a string, this would // lead to an unexpected type conversion on runtime. - if ( ( leftType & TYPE_NUMBER ) && rightString ) + if ( ( leftType & Type_t( TYPE_NUMBER ) ) && rightString ) { throw CompilerException( "cp_invalid_expression_type", "Expected variable of type " + - TypeToString( TYPE_STRING ) + ", got: " + TypeToString( leftType ), + TypeToString( Type_t( TYPE_STRING ) ) + ", got: " + TypeToString( leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } @@ -633,17 +636,17 @@ namespace Compiler auto leftType = m_Left->ExprType( assembler ); auto rightType = m_Right->ExprType( assembler ); - if ( !TypeCheck( leftType, TYPE_NUMBER ) ) + if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + - TypeToString( TYPE_NUMBER ) + " to variable of type " + TypeToString( leftType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + " to variable of type " + TypeToString( leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - if ( !TypeCheck( rightType, TYPE_NUMBER ) ) + if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( TYPE_NUMBER ) + ", got: " + TypeToString( rightType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( rightType ), m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); } } @@ -713,7 +716,7 @@ namespace Compiler if ( !varInfo.m_IsConst ) return NULL; - if ( varInfo.m_Type != TYPE_FUNCTION ) + if ( varInfo.m_Type.m_Bits != TYPE_FUNCTION ) return NULL; return varInfo.m_Function; @@ -796,10 +799,10 @@ namespace Compiler // Perform type checking auto targetType = node->ExprType( assembler ); - if ( !TypeCheck( targetType, TYPE_NUMBER ) ) + if ( !TypeCheck( targetType, Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + - TypeToString( TYPE_NUMBER ) + " to variable of type " + TypeToString( targetType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + " to variable of type " + TypeToString( targetType ), m_LineNr, m_ColNr, m_Token ); } @@ -859,17 +862,17 @@ namespace Compiler if ( opCode != numberOps.end() ) { // Type check: Number - if ( !TypeCheck( leftType, TYPE_NUMBER ) ) + if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( TYPE_NUMBER ) + ", got: " + TypeToString( leftType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - if ( !TypeCheck( rightType, TYPE_NUMBER ) ) + if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( TYPE_NUMBER ) + ", got: " + TypeToString( rightType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( rightType ), m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); } @@ -886,17 +889,17 @@ namespace Compiler auto leftString = !!( leftType & TYPE_STRING ); auto rightString = !!( rightType & TYPE_STRING ); // left = NULL + number - if ( !TypeCheck( leftType, TYPE_NUMBER ) && !leftString ) + if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) && !leftString ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( TYPE_NUMBER | TYPE_STRING ) + ", got: " + TypeToString( leftType ), + TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - if ( !TypeCheck( rightType, TYPE_NUMBER ) && !rightString ) + if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) && !rightString ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( TYPE_NUMBER | TYPE_STRING ) + ", got: " + TypeToString( rightType ), + TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( rightType ), m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); } @@ -985,10 +988,11 @@ namespace Compiler if ( m_NodeId == NODE_RETURN ) { // Check return type match - uint32_t retnType = assembler.CurrentContext()->m_ReturnType; - uint32_t exprType = m_Node ? m_Node->ExprType( assembler ) : TYPE_NULL; + auto type = assembler.CurrentContext()->m_Type; + auto retnType = type.m_ReturnType ? *type.m_ReturnType : Type_t( TYPE_UNKNOWN ); + auto exprType = m_Node ? m_Node->ExprType( assembler ) : Type_t( TYPE_NULL ); - if ( retnType != TYPE_UNKNOWN && exprType != TYPE_UNKNOWN ) + if ( retnType.IsUnknown() && exprType.IsUnknown() ) { if ( !( retnType & exprType ) ) { @@ -1441,7 +1445,7 @@ namespace Compiler auto& varTypeValue = static_cast< ValueNode* >( m_NodeList[ 2 ] )->GetValue(); auto varString = AS_STRING( varName )->GetString(); - uint32_t varType = ( uint32_t ) AS_NUMBER( varTypeValue ); + auto varType = Type_t( ( uint32_t ) AS_NUMBER( varTypeValue ) ); uint32_t varReturnType = TYPE_UNKNOWN; bool isLocal = ( assembler.StackDepth() > 0 ); @@ -1454,9 +1458,9 @@ namespace Compiler // Assign now? if ( m_NodeList[ 1 ] ) { - uint32_t exprType = m_NodeList[ 1 ]->ExprType( assembler ); + auto exprType = m_NodeList[ 1 ]->ExprType( assembler ); - if ( varType != TYPE_UNKNOWN && !( varType & TYPE_AUTO ) ) + if ( !varType.IsUnknown() && !( varType & TYPE_AUTO ) ) { if ( !TypeCheck( varType, exprType ) ) { @@ -1475,7 +1479,7 @@ namespace Compiler { // Compile a named function fn = CompileFunction( false, isConst, false, varString, static_cast< ListNode* >( m_NodeList[ 1 ] ), assembler, &varReturnType ); - varType = TYPE_FUNCTION; + varType = Type_t( TYPE_FUNCTION ); } else { diff --git a/Library/Compiler/AST/AST.h b/Library/Compiler/AST/AST.h index 848d94b..ae1c6d8 100644 --- a/Library/Compiler/AST/AST.h +++ b/Library/Compiler/AST/AST.h @@ -76,35 +76,10 @@ namespace Compiler CO_EXPRESSION = ( 1 << 2 ), }; - enum CompileTypeInfo : uint32_t - { - // Primitives - TYPE_UNKNOWN = ( 0 << 0 ), - TYPE_NULL = ( 1 << 0 ), - TYPE_NUMBER = ( 1 << 1 ), - TYPE_BOOL = ( 1 << 2 ), - - // Objects - TYPE_TABLE = ( 1 << 3 ), - TYPE_CLOSURE = ( 1 << 4 ), - TYPE_FUNCTION = ( 1 << 5 ), - TYPE_INSTANCE = ( 1 << 6 ), - TYPE_NATIVE = ( 1 << 7 ), - TYPE_STRING = ( 1 << 8 ), - TYPE_UPVALUE = ( 1 << 9 ), - TYPE_ARRAY = ( 1 << 10 ), - - // No type (statements) - TYPE_NONE = ( 1 << 11 ), - - // Hint compiler to deduce type - TYPE_AUTO = ( 1 << 12 ), - }; - struct Argument_t { std::string m_Name; - uint32_t m_Type; + Type_t m_Type; int m_LineNr; int m_ColNr; }; @@ -126,7 +101,7 @@ namespace Compiler virtual void Compile( Assembler& assembler, uint32_t options = CO_NONE ) = 0; virtual std::string ToJson( const std::string& ind = "" ) const = 0; - virtual uint32_t ExprType( Assembler& assembler ) const { return Compiler::TYPE_NONE; } + virtual Type_t ExprType( Assembler& assembler ) const { return Compiler::TYPE_NONE; } protected: NodeId m_NodeId; @@ -149,7 +124,7 @@ namespace Compiler public: ValueNode( int lineNr, int colNr, const std::string token, NodeId id, const QScript::Value& value ); void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - uint32_t ExprType( Assembler& assembler ) const override; + Type_t ExprType( Assembler& assembler ) const override; std::string ToJson( const std::string& ind = "" ) const override; QScript::Value& GetValue() { return m_Value; } @@ -165,7 +140,7 @@ namespace Compiler void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - uint32_t ExprType( Assembler& assembler ) const override; + Type_t ExprType( Assembler& assembler ) const override; std::string ToJson( const std::string& ind = "" ) const override; const BaseNode* GetLeft() const; @@ -183,7 +158,7 @@ namespace Compiler void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - uint32_t ExprType( Assembler& assembler ) const override; + Type_t ExprType( Assembler& assembler ) const override; std::string ToJson( const std::string& ind = "" ) const override; const BaseNode* GetNode() const; @@ -199,7 +174,7 @@ namespace Compiler void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - uint32_t ExprType( Assembler& assembler ) const override; + Type_t ExprType( Assembler& assembler ) const override; const std::vector< BaseNode* >& GetList() const; std::string ToJson( const std::string& ind = "" ) const override; @@ -207,6 +182,5 @@ namespace Compiler std::vector< BaseNode* > m_NodeList; }; - uint32_t ResolveReturnType( const ListNode* funcNode, Assembler& assembler ); std::vector< Argument_t > ParseArgsList( ListNode* argNode ); } diff --git a/Library/Compiler/AST/Typing.cpp b/Library/Compiler/AST/Typing.cpp index fdf8991..ab1ec02 100644 --- a/Library/Compiler/AST/Typing.cpp +++ b/Library/Compiler/AST/Typing.cpp @@ -2,30 +2,91 @@ #include "../../Common/Value.h" #include "../../Common/Chunk.h" #include "../Compiler.h" +#include "Typing.h" #include "AST.h" namespace Compiler { - bool TypeCheck( uint32_t targetType, uint32_t exprType, bool strict ) + std::vector< const Type_t* > Type_t::m_Types = {}; + + Type_t* Type_t::AddReturnType( uint32_t bits ) { - if ( targetType == TYPE_UNKNOWN || exprType == TYPE_UNKNOWN ) - return true; + auto type = QS_NEW Type_t( bits ); + m_ReturnType = type; + return type; + } + + Type_t* Type_t::AddArgument( const std::string& name, uint32_t bits ) + { + assert( m_Bits & TYPE_FUNCTION == TYPE_FUNCTION ); + m_ArgTypes.push_back( std::make_pair( name, QS_NEW Type_t( bits ) ) ); + return m_ArgTypes.back().second; + } + + Type_t* Type_t::AddProperty( const std::string& name, uint32_t bits ) + { + assert( m_Bits & TYPE_TABLE == TYPE_TABLE ); + m_PropTypes.push_back( std::make_pair( name, QS_NEW Type_t( bits ) ) ); + return m_PropTypes.back().second; + } + + Type_t* Type_t::AddIndice( uint32_t bits ) + { + assert( m_Bits & TYPE_ARRAY == TYPE_ARRAY ); + m_IndiceTypes.push_back( QS_NEW Type_t( bits ) ); + return m_IndiceTypes.back(); + } + + size_t SaveTypes( const Type_t* types ) + { + if ( !types ) + return NULL; + + Type_t::m_Types.push_back( types ); + return Type_t::m_Types.size() - 1; + } - if ( !strict && ( targetType & TYPE_NULL ) ) + const Type_t* LoadTypes( size_t index ) + { + return Type_t::m_Types[ index ]; + } + + void FreeTypes( const Type_t* types ) + { + if ( !types ) + return; + + FreeTypes( types->m_ReturnType ); + + for ( auto arg : types->m_ArgTypes ) + FreeTypes( arg.second ); + + for ( auto prop : types->m_PropTypes ) + FreeTypes( prop.second ); + + for ( auto indice : types->m_IndiceTypes ) + FreeTypes( indice ); + + delete types; + } + + bool TypeCheck( Type_t targetType, Type_t exprType ) + { + if ( targetType.IsUnknown() || exprType.IsUnknown() ) return true; // Strict type checking return targetType == exprType; } - std::string TypeToString( uint32_t type ) + std::string TypeToString( Type_t type ) { - if ( type == TYPE_UNKNOWN ) + if ( type.IsUnknown() ) return "unknown"; std::string result = ""; - std::map< CompileTypeInfo, std::string > typeStrings ={ + std::map< CompileTypeBits, std::string > typeStrings ={ { TYPE_NULL, "null" }, { TYPE_NUMBER, "num" }, { TYPE_BOOL, "bool" }, @@ -39,7 +100,7 @@ namespace Compiler for ( auto typeString : typeStrings ) { - if ( type & typeString.first ) + if ( type.m_Bits & typeString.first ) { if ( result.length() > 0 ) result += " | " + typeString.second; @@ -51,7 +112,7 @@ namespace Compiler return result.length() > 0 ? result : "not_supported"; } - uint32_t ResolveReturnType( const ListNode* funcNode, Assembler& assembler ) + Type_t ResolveReturnType( const ListNode* funcNode, Assembler& assembler ) { // Is there an explicitly defined return type? auto retnTypeNode = static_cast< ValueNode* >( funcNode->GetList()[ 2 ] ); @@ -62,7 +123,7 @@ namespace Compiler return retnType; // Combine all return statement types - uint32_t returnTypes = TYPE_NULL; + Type_t returnTypes = Type_t( TYPE_NULL ); // Is first return? bool firstReturn = true; @@ -70,12 +131,12 @@ namespace Compiler auto argsList = ParseArgsList( static_cast< ListNode* >( funcNode->GetList()[ 0 ] ) ); for ( auto arg : argsList ) - assembler.AddArgument( arg.m_Name, true, arg.m_LineNr, arg.m_ColNr, arg.m_Type, TYPE_UNKNOWN ); + assembler.AddArgument( arg.m_Name, true, arg.m_LineNr, arg.m_ColNr, arg.m_Type ); std::function< void( const BaseNode* ) > visitNode; visitNode = [ &visitNode, &returnTypes, &firstReturn, &assembler ]( const BaseNode* node ) -> void { - if ( !node || returnTypes == TYPE_UNKNOWN ) + if ( !node || returnTypes.m_Bits == TYPE_UNKNOWN ) return; switch ( node->Type() ) @@ -84,7 +145,7 @@ namespace Compiler { if ( node->Id() == NODE_RETURN ) { - returnTypes |= TYPE_NULL; + returnTypes.m_Bits |= TYPE_NULL; firstReturn = false; } @@ -105,10 +166,10 @@ namespace Compiler auto returnExpressionType = simple->GetNode()->ExprType( assembler ); - if ( returnExpressionType == TYPE_UNKNOWN ) - returnTypes = TYPE_UNKNOWN; + if ( returnExpressionType.m_Bits == TYPE_UNKNOWN ) + returnTypes.m_Bits = TYPE_UNKNOWN; else - returnTypes |= returnExpressionType; + returnTypes.m_Bits |= returnExpressionType.m_Bits; } else { @@ -148,7 +209,7 @@ namespace Compiler return returnTypes; } - uint32_t ValueNode::ExprType( Assembler& assembler ) const + Type_t ValueNode::ExprType( Assembler& assembler ) const { switch ( m_NodeId ) { @@ -174,49 +235,49 @@ namespace Compiler } case NODE_CONSTANT: { - if ( IS_NUMBER( m_Value ) ) return TYPE_NUMBER; - else if ( IS_NULL( m_Value ) ) return TYPE_NULL; - else if ( IS_BOOL( m_Value ) ) return TYPE_BOOL; + if ( IS_NUMBER( m_Value ) ) return Type_t( TYPE_NUMBER ); + else if ( IS_NULL( m_Value ) ) return Type_t( TYPE_NULL ); + else if ( IS_BOOL( m_Value ) ) return Type_t( TYPE_BOOL ); else if ( IS_OBJECT( m_Value ) ) { switch ( AS_OBJECT( m_Value )->m_Type ) { - case QScript::OT_TABLE: return TYPE_TABLE; - case QScript::OT_CLOSURE: return TYPE_CLOSURE; - case QScript::OT_FUNCTION: return TYPE_FUNCTION; - case QScript::OT_NATIVE: return TYPE_NATIVE; - case QScript::OT_STRING: return TYPE_STRING; - case QScript::OT_UPVALUE: return TYPE_UPVALUE; + case QScript::OT_TABLE: return Type_t( TYPE_TABLE ); + case QScript::OT_CLOSURE: return Type_t( TYPE_CLOSURE ); + case QScript::OT_FUNCTION: return Type_t( TYPE_FUNCTION ); + case QScript::OT_NATIVE: return Type_t( TYPE_NATIVE ); + case QScript::OT_STRING: return Type_t( TYPE_STRING ); + case QScript::OT_UPVALUE: return Type_t( TYPE_UPVALUE ); default: break; } } - return TYPE_UNKNOWN; + return Type_t( TYPE_UNKNOWN ); } default: throw CompilerException( "cp_invalid_value_node", "Unknown value node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); } } - uint32_t ComplexNode::ExprType( Assembler& assembler ) const + Type_t ComplexNode::ExprType( Assembler& assembler ) const { switch ( m_NodeId ) { case NODE_ACCESS_PROP: { // TODO: Resolve table property types compile-time - return TYPE_UNKNOWN; + return Type_t( TYPE_UNKNOWN ); } case NODE_ACCESS_ARRAY: { // TODO: Compile-time arrays? - return TYPE_UNKNOWN; + return Type_t( TYPE_UNKNOWN ); } case NODE_ASSIGN: return m_Right->ExprType( assembler ); case NODE_ASSIGNADD: return m_Right->ExprType( assembler ); - case NODE_ASSIGNDIV: return TYPE_NUMBER; - case NODE_ASSIGNMOD: return TYPE_NUMBER; - case NODE_ASSIGNMUL: return TYPE_NUMBER; - case NODE_ASSIGNSUB: return TYPE_NUMBER; + case NODE_ASSIGNDIV: return Type_t( TYPE_NUMBER ); + case NODE_ASSIGNMOD: return Type_t( TYPE_NUMBER ); + case NODE_ASSIGNMUL: return Type_t( TYPE_NUMBER ); + case NODE_ASSIGNSUB: return Type_t( TYPE_NUMBER ); case NODE_CALL: { // Return type @@ -233,13 +294,13 @@ namespace Compiler Variable_t varInfo; if ( assembler.FindLocal( name, &nameIndex, &varInfo ) ) - return varInfo.m_ReturnType; + return varInfo.m_Type.m_ReturnType ? *varInfo.m_Type.m_ReturnType : Type_t( TYPE_NONE ); if ( assembler.FindUpvalue( name, &nameIndex, &varInfo ) ) - return varInfo.m_ReturnType; + return varInfo.m_Type.m_ReturnType ? *varInfo.m_Type.m_ReturnType : Type_t( TYPE_NONE ); if ( assembler.FindGlobal( name, &varInfo ) ) - return varInfo.m_ReturnType; + return varInfo.m_Type.m_ReturnType ? *varInfo.m_Type.m_ReturnType : Type_t( TYPE_NONE ); break; } @@ -251,8 +312,8 @@ namespace Compiler } case NODE_AND: return m_Left->ExprType( assembler ) | m_Right->ExprType( assembler ); case NODE_OR: return m_Left->ExprType( assembler ) | m_Right->ExprType( assembler ); - case NODE_DEC: return TYPE_NUMBER; - case NODE_INC: return TYPE_NUMBER; + case NODE_DEC: return Type_t( TYPE_NUMBER ); + case NODE_INC: return Type_t( TYPE_NUMBER ); case NODE_ADD: { auto leftType = m_Left->ExprType( assembler ); @@ -261,55 +322,55 @@ namespace Compiler if ( ( leftType & TYPE_STRING ) || ( rightType & TYPE_STRING ) ) return TYPE_STRING; - if ( leftType == TYPE_UNKNOWN ) - return TYPE_UNKNOWN; + if ( leftType.IsUnknown() ) + return leftType; - if ( rightType == TYPE_UNKNOWN ) - return TYPE_UNKNOWN; + if ( rightType.IsUnknown() ) + return rightType; return TYPE_NUMBER; } - case NODE_SUB: return TYPE_NUMBER; - case NODE_MUL: return TYPE_NUMBER; - case NODE_DIV: return TYPE_NUMBER; - case NODE_MOD: return TYPE_NUMBER; - case NODE_POW: return TYPE_NUMBER; - case NODE_EQUALS: return TYPE_BOOL; - case NODE_NOTEQUALS: return TYPE_BOOL; - case NODE_GREATERTHAN: return TYPE_BOOL; - case NODE_GREATEREQUAL: return TYPE_BOOL; - case NODE_LESSTHAN: return TYPE_BOOL; - case NODE_LESSEQUAL: return TYPE_BOOL; + case NODE_SUB: return Type_t( TYPE_NUMBER ); + case NODE_MUL: return Type_t( TYPE_NUMBER ); + case NODE_DIV: return Type_t( TYPE_NUMBER ); + case NODE_MOD: return Type_t( TYPE_NUMBER ); + case NODE_POW: return Type_t( TYPE_NUMBER ); + case NODE_EQUALS: return Type_t( TYPE_BOOL ); + case NODE_NOTEQUALS: return Type_t( TYPE_BOOL ); + case NODE_GREATERTHAN: return Type_t( TYPE_BOOL ); + case NODE_GREATEREQUAL: return Type_t( TYPE_BOOL ); + case NODE_LESSTHAN: return Type_t( TYPE_BOOL ); + case NODE_LESSEQUAL: return Type_t( TYPE_BOOL ); default: throw CompilerException( "cp_invalid_complex_node", "Unknown complex node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); } } - uint32_t SimpleNode::ExprType( Assembler& assembler ) const + Type_t SimpleNode::ExprType( Assembler& assembler ) const { switch ( m_NodeId ) { - case NODE_IMPORT: return TYPE_NONE; + case NODE_IMPORT: return Type_t( TYPE_NONE ); case NODE_RETURN: return m_Node->ExprType( assembler ); - case NODE_NOT: return TYPE_BOOL; - case NODE_NEG: return TYPE_NUMBER; + case NODE_NOT: return Type_t( TYPE_BOOL ); + case NODE_NEG: return Type_t( TYPE_NUMBER ); default: throw CompilerException( "cp_invalid_simple_node", "Unknown simple node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); } } - uint32_t ListNode::ExprType( Assembler& assembler ) const + Type_t ListNode::ExprType( Assembler& assembler ) const { switch ( m_NodeId ) { - case NODE_TABLE: return TYPE_TABLE; - case NODE_ARRAY: return TYPE_ARRAY; - case NODE_DO: return TYPE_NONE; - case NODE_FOR: return TYPE_NONE; - case NODE_FUNC: return TYPE_FUNCTION; - case NODE_IF: return TYPE_NONE; - case NODE_SCOPE: return TYPE_NONE; - case NODE_WHILE: return TYPE_NONE; + case NODE_TABLE: return Type_t( TYPE_TABLE ); + case NODE_ARRAY: return Type_t( TYPE_ARRAY ); + case NODE_DO: return Type_t( TYPE_NONE ); + case NODE_FOR: return Type_t( TYPE_NONE ); + case NODE_FUNC: return Type_t( TYPE_FUNCTION ); + case NODE_IF: return Type_t( TYPE_NONE ); + case NODE_SCOPE: return Type_t( TYPE_NONE ); + case NODE_WHILE: return Type_t( TYPE_NONE ); case NODE_INLINE_IF: { return m_NodeList[ 1 ]->ExprType( assembler ) | m_NodeList[ 2 ]->ExprType( assembler ); @@ -320,10 +381,10 @@ namespace Compiler auto assignedType = ( uint32_t ) AS_NUMBER( varTypeValue ); if ( assignedType != TYPE_UNKNOWN && !( assignedType & TYPE_AUTO ) ) - return assignedType; + return Type_t( assignedType ); if ( !m_NodeList[ 1 ] ) - return TYPE_UNKNOWN; + return Type_t( TYPE_UNKNOWN ); return m_NodeList[ 1 ]->ExprType( assembler ); } @@ -335,7 +396,7 @@ namespace Compiler if ( ( type & TYPE_AUTO ) && m_NodeList[ 1 ] ) return m_NodeList[ 1 ]->ExprType( assembler ); - return type; + return Type_t( type ); } default: throw CompilerException( "cp_invalid_list_node", "Unknown list node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); diff --git a/Library/Compiler/AST/Typing.h b/Library/Compiler/AST/Typing.h new file mode 100644 index 0000000..7c373bc --- /dev/null +++ b/Library/Compiler/AST/Typing.h @@ -0,0 +1,64 @@ +#pragma once + +namespace Compiler +{ + enum CompileTypeBits : uint32_t + { + // Primitives + TYPE_UNKNOWN = ( 0 << 0 ), + TYPE_NULL = ( 1 << 0 ), + TYPE_NUMBER = ( 1 << 1 ), + TYPE_BOOL = ( 1 << 2 ), + + // Objects + TYPE_TABLE = ( 1 << 3 ), + TYPE_CLOSURE = ( 1 << 4 ), + TYPE_FUNCTION = ( 1 << 5 ), + TYPE_INSTANCE = ( 1 << 6 ), + TYPE_NATIVE = ( 1 << 7 ), + TYPE_STRING = ( 1 << 8 ), + TYPE_UPVALUE = ( 1 << 9 ), + TYPE_ARRAY = ( 1 << 10 ), + + // No type (statements) + TYPE_NONE = ( 1 << 11 ), + + // Hint compiler to deduce type + TYPE_AUTO = ( 1 << 12 ), + }; + + struct Type_t + { + Type_t( uint32_t bits ) : m_Bits( bits ) + { + m_ReturnType = NULL; + } + + Type_t* AddReturnType( uint32_t bits ); + Type_t* AddArgument( const std::string& name, uint32_t bits ); + Type_t* AddProperty( const std::string& name, uint32_t bits ); + Type_t* AddIndice( uint32_t bits ); + + Type_t operator|( const Type_t& other ) const { return Type_t( m_Bits | other.m_Bits ); } + uint32_t operator&( const Type_t& other ) const { return m_Bits & other.m_Bits; } + uint32_t operator&( uint32_t bits ) const { return m_Bits & bits; } + bool operator==( const Type_t& other ) const { return m_Bits == other.m_Bits; } + + bool IsUnknown() const { return m_Bits == TYPE_UNKNOWN; } + + uint32_t m_Bits; + Type_t* m_ReturnType; // Function returns + + std::vector< std::pair< std::string, Type_t* > > m_ArgTypes; // Function arguments + std::vector< std::pair< std::string, Type_t* > > m_PropTypes; // Table props + std::vector< Type_t* > m_IndiceTypes; // Array indices + + static std::vector< const Type_t* > m_Types; + }; + + size_t SaveTypes( const Type_t* types ); + const Type_t* LoadTypes( size_t index ); + void FreeTypes( const Type_t* types ); + + Type_t ResolveReturnType( const ListNode* funcNode, Assembler& assembler ); +} diff --git a/Library/Compiler/Compiler.cpp b/Library/Compiler/Compiler.cpp index cfb54d8..6edd62c 100644 --- a/Library/Compiler/Compiler.cpp +++ b/Library/Compiler/Compiler.cpp @@ -4,6 +4,7 @@ #include "Instructions.h" #include "Compiler.h" +#include "Typing.h" #define BEGIN_COMPILER \ Object::AllocateString = &Compiler::AllocateString; \ @@ -115,7 +116,7 @@ namespace QScript } } - std::vector< std::pair< uint32_t, uint32_t > > Typer( const std::string& source, const Config_t& config ) + /*std::vector< std::pair< uint32_t, uint32_t > > Typer( const std::string& source, const Config_t& config ) { BEGIN_COMPILER; @@ -165,7 +166,7 @@ namespace QScript Compiler::Variable_t varInfo; if ( assembler.FindGlobal( name, &varInfo ) ) - retnType = varInfo.m_ReturnType; + retnType = varInfo.m_Type->m_ReturnType ? varInfo.m_Type->m_ReturnType->m_Bits : Compiler::TYPE_NONE; break; } @@ -267,7 +268,7 @@ namespace QScript // Rethrow throw; } - } + }*/ std::vector< Compiler::BaseNode* > GenerateAST( const std::string& source ) { @@ -535,9 +536,9 @@ namespace Compiler { // Fill out globals for REPL for ( auto identifier : config.m_Globals ) - AddGlobal( identifier, -1, -1 ); + AddGlobal( identifier, false, -1, -1, Type_t( TYPE_UNKNOWN ), NULL ); - CreateFunction( "
", true, TYPE_UNKNOWN, true, true, chunk ); + CreateFunction( "
", true, Type_t( TYPE_UNKNOWN ), true, true, chunk ); } void Assembler::Release() @@ -590,15 +591,15 @@ namespace Compiler return m_Functions.back().m_Stack; } - QScript::FunctionObject* Assembler::CreateFunction( const std::string& name, bool isConst, uint32_t retnType, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ) + QScript::FunctionObject* Assembler::CreateFunction( const std::string& name, bool isConst, Type_t type, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ) { auto function = QS_NEW QScript::FunctionObject( name, chunk ); - auto context = FunctionContext_t{ function, QS_NEW Assembler::Stack_t(), retnType }; + auto context = FunctionContext_t{ function, QS_NEW Assembler::Stack_t(), type }; m_Functions.push_back( context ); if ( addLocal ) - AddLocal( isAnonymous ? "" : name, isConst, -1, -1, TYPE_FUNCTION, retnType ); + AddLocal( isAnonymous ? "" : name, isConst, -1, -1, type ); return function; } @@ -620,9 +621,9 @@ namespace Compiler m_Functions.pop_back(); } - void Assembler::AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, uint32_t type, uint32_t returnType ) + void Assembler::AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type ) { - auto variable = Variable_t{ name, isConstant, type, returnType, NULL }; + auto variable = Variable_t{ name, isConstant, type, NULL }; if ( m_Config.m_IdentifierCb ) m_Config.m_IdentifierCb( lineNr, colNr, variable, "Argument" ); @@ -630,16 +631,11 @@ namespace Compiler m_FunctionArgs.push_back( variable ); } - uint32_t Assembler::AddLocal( const std::string& name, int lineNr, int colNr ) - { - return AddLocal( name, false, lineNr, colNr, TYPE_UNKNOWN, TYPE_UNKNOWN ); - } - - uint32_t Assembler::AddLocal( const std::string& name, bool isConstant, int lineNr, int colNr, uint32_t type, uint32_t returnType, QScript::FunctionObject* fn ) + uint32_t Assembler::AddLocal( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type, QScript::FunctionObject* fn ) { auto stack = CurrentStack(); - auto variable = Variable_t{ name, isConstant, type, returnType, fn }; + auto variable = Variable_t{ name, isConstant, type, fn }; if ( m_Config.m_IdentifierCb ) m_Config.m_IdentifierCb( lineNr, colNr, variable, "Local" ); @@ -716,17 +712,12 @@ namespace Compiler return false; } - bool Assembler::AddGlobal( const std::string& name, int lineNr, int colNr ) - { - return AddGlobal( name, false, lineNr, colNr, TYPE_UNKNOWN, TYPE_UNKNOWN, NULL ); - } - - bool Assembler::AddGlobal( const std::string& name, bool isConstant, int lineNr, int colNr, uint32_t type, uint32_t returnType, QScript::FunctionObject* fn ) + bool Assembler::AddGlobal( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type, QScript::FunctionObject* fn ) { if ( m_Globals.find( name ) != m_Globals.end() ) return false; - Variable_t global = Variable_t{ name, isConstant, type, returnType, fn }; + Variable_t global = Variable_t{ name, isConstant, type, fn }; m_Globals.insert( std::make_pair( name, global ) ); if ( m_Config.m_IdentifierCb ) diff --git a/Library/Compiler/Compiler.h b/Library/Compiler/Compiler.h index 96eb9ca..ed6fd55 100644 --- a/Library/Compiler/Compiler.h +++ b/Library/Compiler/Compiler.h @@ -2,12 +2,15 @@ #include "Tokens.h" #include "AST/AST.h" +#include "Typing.h" struct VM_t; class Object; namespace Compiler { + struct Type_t; + std::vector< Token_t > Lexer( const std::string& source ); std::vector< BaseNode* > GenerateIR( const std::vector< Token_t >& tokens ); // std::vector< BaseNode* > OptimizeIR( std::vector< BaseNode* > nodes ); @@ -31,10 +34,15 @@ namespace Compiler struct Variable_t { + Variable_t() : m_Type( TYPE_UNKNOWN ) + { + m_IsConst = false; + m_Function = NULL; + } + std::string m_Name; bool m_IsConst; - uint32_t m_Type; - uint32_t m_ReturnType; + Type_t m_Type; QScript::FunctionObject* m_Function; }; @@ -69,25 +77,23 @@ namespace Compiler { QScript::FunctionObject* m_Func; Stack_t* m_Stack; - uint32_t m_ReturnType; + Type_t m_Type; std::vector< Upvalue_t > m_Upvalues; }; Assembler( QScript::Chunk_t* chunk, const QScript::Config_t& config ); - void AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, uint32_t type, uint32_t returnType = TYPE_UNKNOWN ); - bool AddGlobal( const std::string& name, int lineNr, int colNr ); + void AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type ); bool AddGlobal( const std::string& name, bool isConstant, int lineNr, int colNr, - uint32_t type, uint32_t returnType = TYPE_UNKNOWN, QScript::FunctionObject* fn = NULL ); + Type_t type, QScript::FunctionObject* fn = NULL ); uint32_t AddLocal( const std::string& name, bool isConstant, int lineNr, int colNr, - uint32_t type, uint32_t returnType = TYPE_UNKNOWN, QScript::FunctionObject* fn = NULL ); + Type_t type, QScript::FunctionObject* fn = NULL ); - uint32_t AddLocal( const std::string& name, int lineNr, int colNr ); uint32_t AddUpvalue( FunctionContext_t* context, uint32_t index, bool isLocal, int lineNr, int colNr, Variable_t* varInfo ); void ClearArguments(); const QScript::Config_t& Config() const; - QScript::FunctionObject* CreateFunction( const std::string& name, bool isConst, uint32_t retnType, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ); + QScript::FunctionObject* CreateFunction( const std::string& name, bool isConst, Type_t type, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ); const std::vector< Variable_t >& CurrentArguments(); QScript::Chunk_t* CurrentChunk(); const FunctionContext_t* CurrentContext(); diff --git a/Library/Compiler/IRGenerator.cpp b/Library/Compiler/IRGenerator.cpp index 0964230..86c00be 100644 --- a/Library/Compiler/IRGenerator.cpp +++ b/Library/Compiler/IRGenerator.cpp @@ -3,6 +3,7 @@ #include "Compiler.h" #include "Instructions.h" +#include "Typing.h" #include "IR.h" namespace Compiler @@ -17,9 +18,9 @@ namespace Compiler return IS_STRING( static_cast< ValueNode* >( node )->GetValue() ); } - CompileTypeInfo ResolveTypeDef( ParserState& parserState ) + CompileTypeBits ResolveTypeDef( ParserState& parserState ) { - std::map< Token, CompileTypeInfo > typeMap = { + std::map< Token, CompileTypeBits > typeMap = { { TOK_AUTO, TYPE_AUTO }, { TOK_STRING, TYPE_STRING }, { TOK_BOOL, TYPE_BOOL }, @@ -85,7 +86,7 @@ namespace Compiler argName->LineNr(), argName->ColNr(), argName->Token() ); } - std::vector< CompileTypeInfo > validTypes ={ + std::vector< CompileTypeBits > validTypes ={ TYPE_BOOL, TYPE_STRING, TYPE_NUMBER From 26aacd74b2e9d35ac6129a42447384e1a7a4d788 Mon Sep 17 00:00:00 2001 From: fakelag <35497506+fakelag@users.noreply.github.com> Date: Mon, 29 Jun 2020 20:48:32 +0300 Subject: [PATCH 2/3] Type refactoring (WIP) --- CLI/CLI.cpp | 64 ++--- Includes/QScript.h | 8 +- Library/Common/Object.h | 20 +- Library/Compiler/AST/AST.cpp | 304 ++++++++++++++---------- Library/Compiler/AST/AST.h | 54 ++++- Library/Compiler/AST/ToJson.cpp | 11 + Library/Compiler/AST/Typing.cpp | 392 ++++++++++++++----------------- Library/Compiler/AST/Typing.h | 64 +---- Library/Compiler/Compiler.cpp | 74 ++++-- Library/Compiler/Compiler.h | 35 ++- Library/Compiler/IRGenerator.cpp | 73 +++--- Library/Compiler/Types.cpp | 247 +++++++++++++++++++ Library/Compiler/Types.h | 70 ++++++ Library/Library.vcxproj | 2 + Library/Library.vcxproj.filters | 6 + Library/STL/NativeModule.h | 6 + Library/STL/System.cpp | 6 +- Library/STL/Time.cpp | 3 +- Tests/TestCompiler.cpp | 39 ++- Tests/Tests.cpp | 4 +- Tests/Tests.vcxproj | 1 + Tests/Tests.vcxproj.filters | 3 + 22 files changed, 937 insertions(+), 549 deletions(-) create mode 100644 Library/Compiler/Types.cpp create mode 100644 Library/Compiler/Types.h diff --git a/CLI/CLI.cpp b/CLI/CLI.cpp index 08bc987..ffc3484 100644 --- a/CLI/CLI.cpp +++ b/CLI/CLI.cpp @@ -105,38 +105,38 @@ int main( int argc, char* argv[] ) } else if ( GetArg( "--typer", argc, argv, &next ) ) { - for (;;) - { - try - { - std::string source = input; - - if ( source.length() == 0 ) - { - std::cout << "Typer >"; - std::getline( std::cin, source ); - } - - auto exprTypes = QScript::Typer( source ); - - for ( auto type : exprTypes ) - { - if ( type.second != 1024 /* TYPE_NONE */ ) - { - std::cout << Compiler::TypeToString( type.first ) - << " -> " << Compiler::TypeToString( type.second ) << std::endl; - } - else - { - std::cout << Compiler::TypeToString( type.first ) << std::endl; - } - } - } - EXCEPTION_HANDLING; - - if ( input.length() > 0 ) - break; - } + //for (;;) + //{ + // try + // { + // std::string source = input; + + // if ( source.length() == 0 ) + // { + // std::cout << "Typer >"; + // std::getline( std::cin, source ); + // } + + // auto exprTypes = QScript::Typer( source ); + + // for ( auto type : exprTypes ) + // { + // if ( type.second != 1024 /* TYPE_NONE */ ) + // { + // std::cout << Compiler::TypeToString( type.first ) + // << " -> " << Compiler::TypeToString( type.second ) << std::endl; + // } + // else + // { + // std::cout << Compiler::TypeToString( type.first ) << std::endl; + // } + // } + // } + // EXCEPTION_HANDLING; + + // if ( input.length() > 0 ) + // break; + //} } else if ( GetArg( "--json", argc, argv, &next ) ) { diff --git a/Includes/QScript.h b/Includes/QScript.h index edf9a49..814feb7 100644 --- a/Includes/QScript.h +++ b/Includes/QScript.h @@ -10,7 +10,7 @@ #endif #endif -#include "Typing.h" +#include "../Library/Compiler/Types.h" struct VM_t; @@ -19,8 +19,8 @@ namespace Compiler class BaseNode; struct Variable_t; - std::string TypeToString( Type_t type ); - bool TypeCheck( Type_t targetType, Type_t exprType ); + std::string TypeToString( const Type_t& type ); + // bool TypeCheck( Type_t targetType, Type_t exprType ); } namespace QScript @@ -66,7 +66,7 @@ namespace QScript Chunk_t* AllocChunk(); FunctionObject* Compile( const std::string& source, const Config_t& config = Config_t( true ) ); - std::vector< std::pair< uint32_t, uint32_t > > Typer( const std::string& source, const Config_t& config = Config_t( false ) ); + // std::vector< std::pair< uint32_t, uint32_t > > Typer( const std::string& source, const Config_t& config = Config_t( false ) ); std::vector< Compiler::BaseNode* > GenerateAST( const std::string& source ); void FreeChunk( Chunk_t* chunk ); diff --git a/Library/Common/Object.h b/Library/Common/Object.h index 0bbe50e..3809a79 100644 --- a/Library/Common/Object.h +++ b/Library/Common/Object.h @@ -1,6 +1,6 @@ #pragma once #include "Value.h" -#include "Typing.h" +#include "../Library/Compiler/Types.h" namespace QScript { @@ -24,12 +24,6 @@ namespace QScript class FunctionObject : public Object { public: - struct Arg_t - { - std::string m_Name; - Compiler::Type_t m_Type; - }; - FORCEINLINE FunctionObject( const std::string& name, Chunk_t* chunk ) { m_Type = OT_FUNCTION; @@ -40,22 +34,18 @@ namespace QScript FORCEINLINE void Rename( const std::string& newName ) { m_Name = newName; } FORCEINLINE const std::string& GetName() const { return m_Name; } - FORCEINLINE int NumArgs() const { return ( int ) m_Arguments.size(); } + FORCEINLINE int NumArgs() const { return m_Arity; } FORCEINLINE int NumUpvalues() const { return m_NumUpvalues; } FORCEINLINE Chunk_t* GetChunk() const { return m_Chunk; } - FORCEINLINE const std::vector< Arg_t >& GetArgs() const { return m_Arguments; } - FORCEINLINE void SetUpvalues( int numUpvalues ) { ++m_NumUpvalues; } - FORCEINLINE void AddArgument( const std::string& name, Compiler::Type_t type ) - { - m_Arguments.push_back( Arg_t{ name, type } ); - } + FORCEINLINE void SetUpvalues( int numUpvalues ) { ++m_NumUpvalues; } + FORCEINLINE void SetNumArgs( int numArgs ) { m_Arity = numArgs; } private: std::string m_Name; int m_NumUpvalues; + int m_Arity; Chunk_t* m_Chunk; - std::vector< Arg_t > m_Arguments; }; class NativeFunctionObject : public Object diff --git a/Library/Compiler/AST/AST.cpp b/Library/Compiler/AST/AST.cpp index 6c71ba6..e7b3dab 100644 --- a/Library/Compiler/AST/AST.cpp +++ b/Library/Compiler/AST/AST.cpp @@ -1,11 +1,12 @@ #include "QLibPCH.h" #include "Instructions.h" -#include "Typing.h" #include "../../Common/Chunk.h" #include "../../STL/NativeModule.h" #include "../Compiler.h" +#include "Typing.h" + #define COMPILE_EXPRESSION( options ) (options | CO_EXPRESSION) #define COMPILE_STATEMENT( options ) (options & ~CO_EXPRESSION) #define COMPILE_ASSIGN_TARGET( options ) (options | CO_ASSIGN) @@ -147,7 +148,7 @@ namespace Compiler } } - std::vector< Argument_t > ParseArgsList( ListNode* argNode ) + std::vector< Argument_t > ParseArgsList( ListNode* argNode, Assembler& assembler ) { std::vector< Argument_t > argsList; @@ -162,21 +163,22 @@ namespace Compiler auto varTypeNode = listNode->GetList()[ 2 ]; auto varName = static_cast< ValueNode* >( varNameNode )->GetValue(); - uint32_t varType = ( uint32_t ) AS_NUMBER( static_cast< ValueNode* >( varTypeNode )->GetValue() ); + const Type_t* varType = static_cast< TypeNode* >( varTypeNode )->GetType(); - switch ( varType ) + switch ( varType->m_Bits ) { case TYPE_NUMBER: case TYPE_STRING: case TYPE_UNKNOWN: case TYPE_BOOL: { - argsList.push_back( Argument_t{ AS_STRING( varName )->GetString(), varType, varNameNode->LineNr(), varNameNode->ColNr() } ); + argsList.push_back( Argument_t( AS_STRING( varName )->GetString(), DeepCopyType( *varType, assembler.RegisterType( QS_NEW Type_t ) ), + varNameNode->LineNr(), varNameNode->ColNr() ) ); break; } default: { - throw CompilerException( "cp_invalid_function_arg_type", "Invalid argument type: " + TypeToString( varType ), + throw CompilerException( "cp_invalid_function_arg_type", "Invalid argument type: " + TypeToString( *varType ), arg->LineNr(), arg->ColNr(), arg->Token() ); } } @@ -184,8 +186,8 @@ namespace Compiler } case NODE_NAME: { - argsList.push_back( Argument_t{ AS_STRING( static_cast< ValueNode* >( arg )->GetValue() )->GetString(), - TYPE_UNKNOWN, arg->LineNr(), arg->ColNr() } ); + argsList.push_back( Argument_t( AS_STRING( static_cast< ValueNode* >( arg )->GetValue() )->GetString(), + DeepCopyType( Type_t( TYPE_UNKNOWN ), assembler.RegisterType( QS_NEW Type_t ) ), arg->LineNr(), arg->ColNr() ) ); break; } default: @@ -200,32 +202,35 @@ namespace Compiler } QScript::FunctionObject* CompileFunction( bool isAnonymous, bool isConst, bool isMember, const std::string& name, ListNode* funcNode, - Assembler& assembler, Type_t* outReturnType = NULL, int lineNr = -1, int colNr = -1 ) + Assembler& assembler, const Type_t** outType = NULL, int lineNr = -1, int colNr = -1 ) { auto chunk = assembler.CurrentChunk(); auto& nodeList = funcNode->GetList(); auto argNode = static_cast< ListNode* >( nodeList[ 0 ] ); - auto returnType = ResolveReturnType( funcNode, assembler ); - // Allocate chunk & create function - auto function = assembler.CreateFunction( name, isConst, returnType, isAnonymous, !isMember, QScript::AllocChunk() ); + auto funcType = assembler.RegisterType( QS_NEW Type_t( TYPE_FUNCTION ) ); + funcType->m_ReturnType = QS_NEW Type_t; - if ( outReturnType ) - *outReturnType = returnType; + ResolveReturnType( funcNode, assembler, funcType->m_ReturnType ); + + // Allocate chunk & create function + auto function = assembler.CreateFunction( name, isConst, funcType, isAnonymous, !isMember, QScript::AllocChunk() ); if ( isMember ) - assembler.AddLocal( "this", false, -1, -1, TYPE_TABLE ); + assembler.AddLocal( "this", false, -1, -1, &Type_t( TYPE_TABLE ) ); assembler.PushScope(); // Create args in scope - auto argsList = ParseArgsList( argNode ); - std::for_each( argsList.begin(), argsList.end(), [ &assembler, &function ]( const Argument_t& item ) { - function->AddArgument( item.m_Name, item.m_Type ); + auto argsList = ParseArgsList( argNode, assembler ); + std::for_each( argsList.begin(), argsList.end(), [ &assembler, &function, &funcType ]( const Argument_t& item ) { + funcType->m_ArgTypes.push_back( NamedType_t{ item.m_Name, item.m_Type } ); // Give type ownership to function type assembler.AddLocal( item.m_Name, true, item.m_LineNr, item.m_ColNr, item.m_Type ); } ); + function->SetNumArgs( argsList.size() ); + // Compile function body for ( auto node : static_cast< ListNode* >( nodeList[ 1 ] )->GetList() ) node->Compile( assembler, COMPILE_STATEMENT( 0 ) ); @@ -249,6 +254,17 @@ namespace Compiler EmitByte( ENCODE_LONG( upvalue.m_Index, 3 ), chunk ); } + if ( outType ) + { + *outType = funcType; + } + else + { + // Free temporary return type holder + FreeTypes( assembler.UnregisterType( funcType ) ); + } + + return function; } @@ -259,6 +275,7 @@ namespace Compiler m_Token = token; m_NodeType = type; m_NodeId = id; + m_ExprType = QS_NEW Type_t( TYPE_NONE ); } TermNode::TermNode( int lineNr, int colNr, const std::string token, NodeId id ) @@ -266,6 +283,12 @@ namespace Compiler { } + void TermNode::Release() + { + FreeTypes( m_ExprType ); + m_ExprType = NULL; + } + void TermNode::Compile( Assembler& assembler, uint32_t options ) { auto chunk = assembler.CurrentChunk(); @@ -279,14 +302,16 @@ namespace Compiler case NODE_RETURN: { // Check that the function can return null - auto& type = assembler.CurrentContext()->m_Type; - auto retnType = type.m_ReturnType ? *type.m_ReturnType : Type_t( TYPE_UNKNOWN ); + auto type = assembler.CurrentContext()->m_Type; - if ( !retnType.IsUnknown() && !( retnType & TYPE_NULL ) ) + if ( type->m_ReturnType ) { - throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( retnType.m_Bits ) + ", got: " + TypeToString( TYPE_NULL ), - LineNr(), ColNr(), Token() ); + if ( !type->m_ReturnType->IsAssignable( &Type_t( TYPE_NULL ) ) ) + { + throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + + TypeToString( *type->m_ReturnType ) + ", got: " + TypeToString( Type_t( TYPE_NULL ) ), + LineNr(), ColNr(), Token() ); + } } EmitByte( QScript::OpCode::OP_LOAD_NULL, chunk ); @@ -306,6 +331,12 @@ namespace Compiler m_Value = value; } + void ValueNode::Release() + { + FreeTypes( m_ExprType ); + m_ExprType = NULL; + } + void ValueNode::Compile( Assembler& assembler, uint32_t options ) { auto chunk = assembler.CurrentChunk(); @@ -474,14 +505,17 @@ namespace Compiler m_Right->Release(); delete m_Right; } + + FreeTypes( m_ExprType ); + m_ExprType = NULL; } - const BaseNode* ComplexNode::GetLeft() const + BaseNode* ComplexNode::GetLeft() { return m_Left; } - const BaseNode* ComplexNode::GetRight() const + BaseNode* ComplexNode::GetRight() { return m_Right; } @@ -573,10 +607,10 @@ namespace Compiler auto leftType = m_Left->ExprType( assembler ); auto rightType = m_Right->ExprType( assembler ); - if ( !( leftType & TYPE_NULL ) && !TypeCheck( leftType, rightType ) ) + if ( !leftType->IsAssignable( rightType ) ) { throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + - TypeToString( rightType ) + " to variable of type " + TypeToString( leftType ), + TypeToString( *rightType ) + " to variable of type " + TypeToString( *leftType ), m_LineNr, m_ColNr, m_Token ); } break; @@ -587,70 +621,49 @@ namespace Compiler case NODE_ASSIGNMUL: case NODE_ASSIGNSUB: { - // TODO: Faster instruction selection based on number addition or string concatenation - bool isStringConcat = false; - RequireAssignability( m_Left ); // Load both values to the top of the stack m_Left->Compile( assembler, COMPILE_EXPRESSION( options ) ); m_Right->Compile( assembler, COMPILE_EXPRESSION( options ) ); - // Perform type checking - if ( m_NodeId == NODE_ASSIGNADD ) - { - // Either add or concat (strings) - auto leftType = m_Left->ExprType( assembler ); - auto rightType = m_Right->ExprType( assembler ); + auto acceptedTypes = Type_t( m_NodeId == NODE_ASSIGNADD + ? TYPE_NUMBER | TYPE_STRING + : TYPE_NUMBER ); - auto leftString = !!( leftType & TYPE_STRING ); - auto rightString = !!( rightType & TYPE_STRING ); + // Either addition or concatenation (strings) + auto leftType = m_Left->ExprType( assembler ); + auto rightType = m_Right->ExprType( assembler ); - if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) && !leftString ) - { - throw CompilerException( "cp_invalid_expression_type", "Expected variable of type " + - TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( leftType ), - m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); - } + if ( !acceptedTypes.IsAssignable( leftType ) ) + { + throw CompilerException( "cp_invalid_expression_type", "Expected variable of type " + + TypeToString( acceptedTypes ) + ", got: " + TypeToString( *leftType ), + m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); + } - if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) && !rightString ) - { - throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( rightType ), - m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); - } + if ( !acceptedTypes.IsAssignable( rightType ) ) + { + throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + + TypeToString( acceptedTypes ) + ", got: " + TypeToString( *rightType ), + m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); + } - // If the variable is a num, but right hand operand is a string, this would - // lead to an unexpected type conversion on runtime. - if ( ( leftType & Type_t( TYPE_NUMBER ) ) && rightString ) + if ( m_NodeId == NODE_ASSIGNADD ) + { + // If the variable is strictly a num, but right hand operand is a string, this would + // lead to an unexpected type conversion on runtime. Where a compile-time num variable + // is now a string. + if ( leftType->IsPrimitive( TYPE_NUMBER ) && rightType->HasPrimitive( TYPE_STRING ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected variable of type " + - TypeToString( Type_t( TYPE_STRING ) ) + ", got: " + TypeToString( leftType ), + TypeToString( Type_t( TYPE_STRING ) ) + ", got: " + TypeToString( *leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - - isStringConcat = leftString; } - else - { - // Both types must be numbers - auto leftType = m_Left->ExprType( assembler ); - auto rightType = m_Right->ExprType( assembler ); - - if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) ) - { - throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + - TypeToString( Type_t( TYPE_NUMBER ) ) + " to variable of type " + TypeToString( leftType ), - m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); - } - if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) ) - { - throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( rightType ), - m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); - } - } + // TODO: Faster instruction selection based on number addition or string concatenation + // bool isStringConcat = m_NodeId == NODE_ASSIGNADD && leftType->IsPrimitive( TYPE_STRING ); // Add respective nullary operator std::map< NodeId, QScript::OpCode > map = { @@ -717,7 +730,7 @@ namespace Compiler if ( !varInfo.m_IsConst ) return NULL; - if ( varInfo.m_Type.m_Bits != TYPE_FUNCTION ) + if ( !varInfo.m_Type->IsPrimitive( TYPE_FUNCTION ) ) return NULL; return varInfo.m_Function; @@ -800,10 +813,11 @@ namespace Compiler // Perform type checking auto targetType = node->ExprType( assembler ); - if ( !TypeCheck( targetType, Type_t( TYPE_NUMBER ) ) ) + + if ( !targetType->IsAssignable( &Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + - TypeToString( Type_t( TYPE_NUMBER ) ) + " to variable of type " + TypeToString( targetType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + " to variable of type " + TypeToString( *targetType ), m_LineNr, m_ColNr, m_Token ); } @@ -863,17 +877,17 @@ namespace Compiler if ( opCode != numberOps.end() ) { // Type check: Number - if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) ) + if ( !leftType->IsAssignable( &Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( leftType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( *leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) ) + if ( !rightType->IsAssignable( &Type_t( TYPE_NUMBER ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( rightType ), + TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( *rightType ), m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); } @@ -881,32 +895,30 @@ namespace Compiler } else if ( ( opCode = otherOps.find( m_NodeId ) ) != otherOps.end() ) { - // TODO: instruction selection - bool isStringConcat = false; - if ( m_NodeId == NODE_ADD ) { // Type check: String or number - auto leftString = !!( leftType & TYPE_STRING ); - auto rightString = !!( rightType & TYPE_STRING ); + auto acceptedTypes = Type_t( TYPE_NUMBER | TYPE_STRING ); + // left = NULL + number - if ( !TypeCheck( leftType, Type_t( TYPE_NUMBER ) ) && !leftString ) + if ( !acceptedTypes.IsAssignable( leftType ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( leftType ), + TypeToString( acceptedTypes ) + ", got: " + TypeToString( *leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - if ( !TypeCheck( rightType, Type_t( TYPE_NUMBER ) ) && !rightString ) + if ( !acceptedTypes.IsAssignable( rightType ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( Type_t( TYPE_NUMBER | TYPE_STRING ) ) + ", got: " + TypeToString( rightType ), + TypeToString( acceptedTypes ) + ", got: " + TypeToString( *rightType ), m_Right->LineNr(), m_Right->ColNr(), m_Right->Token() ); } - - isStringConcat = rightString || leftString; } + // TODO: Instruction selection + // bool isStringConcat = rightType->IsPrimitive( TYPE_STRING ) && leftType->IsPrimitive( TYPE_STRING ); + EmitByte( opCode->second, chunk ); } else @@ -937,9 +949,12 @@ namespace Compiler m_Node->Release(); delete m_Node; } + + FreeTypes( m_ExprType ); + m_ExprType = NULL; } - const BaseNode* SimpleNode::GetNode() const + BaseNode* SimpleNode::GetNode() { return m_Node; } @@ -990,17 +1005,14 @@ namespace Compiler { // Check return type match auto type = assembler.CurrentContext()->m_Type; - auto retnType = type.m_ReturnType ? *type.m_ReturnType : Type_t( TYPE_UNKNOWN ); - auto exprType = m_Node ? m_Node->ExprType( assembler ) : Type_t( TYPE_NULL ); + auto retnType = type->m_ReturnType ? type->m_ReturnType : &Type_t( TYPE_UNKNOWN ); + auto exprType = m_Node ? m_Node->ExprType( assembler ) : &Type_t( TYPE_NULL ); - if ( retnType.IsUnknown() && exprType.IsUnknown() ) + if ( !retnType->IsAssignable( exprType ) ) { - if ( !( retnType & exprType ) ) - { - throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( retnType ) + ", got: " + TypeToString( exprType ), - LineNr(), ColNr(), Token() ); - } + throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + + TypeToString( *retnType ) + ", got: " + TypeToString( *exprType ), + LineNr(), ColNr(), Token() ); } } @@ -1041,6 +1053,9 @@ namespace Compiler } m_NodeList.clear(); + + FreeTypes( m_ExprType ); + m_ExprType = NULL; } const std::vector< BaseNode* >& ListNode::GetList() const @@ -1086,7 +1101,7 @@ namespace Compiler if ( !isLocal ) { // Global variable - if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, TYPE_TABLE ) ) + if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, &Type_t( TYPE_TABLE ) ) ) { throw CompilerException( "cp_identifier_already_exists", "Identifier \"" + varNameString + "\" already exists", m_LineNr, m_ColNr, m_Token ); @@ -1097,7 +1112,7 @@ namespace Compiler else { // Local variable - assembler.AddLocal( varNameString, true, lineNr, colNr, TYPE_TABLE ); + assembler.AddLocal( varNameString, true, lineNr, colNr, &Type_t( TYPE_TABLE ) ); } } else @@ -1235,7 +1250,7 @@ namespace Compiler if ( !isLocal ) { - if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, TYPE_ARRAY ) ) + if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, &Type_t( TYPE_ARRAY ) ) ) { throw CompilerException( "cp_identifier_already_exists", "Identifier \"" + varNameString + "\" already exists", m_LineNr, m_ColNr, m_Token ); @@ -1245,7 +1260,7 @@ namespace Compiler } else { - assembler.AddLocal( varNameString, true, lineNr, colNr, TYPE_ARRAY ); + assembler.AddLocal( varNameString, true, lineNr, colNr, &Type_t( TYPE_ARRAY ) ); } } @@ -1446,11 +1461,9 @@ namespace Compiler { // m_NodeList[ 0 ] should be NODE_NAME and is validated during parsing auto& varName = static_cast< ValueNode* >( m_NodeList[ 0 ] )->GetValue(); - auto& varTypeValue = static_cast< ValueNode* >( m_NodeList[ 2 ] )->GetValue(); - auto varString = AS_STRING( varName )->GetString(); - auto varType = Type_t( ( uint32_t ) AS_NUMBER( varTypeValue ) ); - uint32_t varReturnType = TYPE_UNKNOWN; + + const Type_t* varType = static_cast< TypeNode* >( m_NodeList[ 2 ] )->GetType(); bool isLocal = ( assembler.StackDepth() > 0 ); bool isConst = ( m_NodeId == NODE_CONSTVAR ); @@ -1464,26 +1477,25 @@ namespace Compiler { auto exprType = m_NodeList[ 1 ]->ExprType( assembler ); - if ( !varType.IsUnknown() && !( varType & TYPE_AUTO ) ) + if ( varType->IsAuto() ) { - if ( !TypeCheck( varType, exprType ) ) + // Deduce type from expression + varType = exprType; + } + else + { + if ( !varType->IsAssignable( exprType ) ) { throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + - TypeToString( exprType ) + " to variable of type " + TypeToString( varType ), + TypeToString( *exprType ) + " to variable of type " + TypeToString( *varType ), m_NodeList[ 1 ]->LineNr(), m_NodeList[ 1 ]->ColNr(), m_NodeList[ 1 ]->Token() ); } } - else if ( varType & TYPE_AUTO ) - { - // Deduce type from expression - varType = exprType; - } if ( m_NodeList[ 1 ]->Id() == NODE_FUNC ) { // Compile a named function - fn = CompileFunction( false, isConst, false, varString, static_cast< ListNode* >( m_NodeList[ 1 ] ), assembler, &varReturnType, lineNr, colNr ); - varType = TYPE_FUNCTION; + fn = CompileFunction( false, isConst, false, varString, static_cast< ListNode* >( m_NodeList[ 1 ] ), assembler, &varType, lineNr, colNr ); } else { @@ -1493,11 +1505,11 @@ namespace Compiler if ( isLocal ) { - assembler.AddLocal( varString, isConst, lineNr, colNr, varType, varReturnType, fn ); + assembler.AddLocal( varString, isConst, lineNr, colNr, varType, fn ); } else { - if ( !assembler.AddGlobal( varString, isConst, lineNr, colNr, varType, varReturnType, fn ) ) + if ( !assembler.AddGlobal( varString, isConst, lineNr, colNr, varType, fn ) ) { throw CompilerException( "cp_identifier_already_exists", "Identifier \"" + varString + "\" already exists", lineNr, colNr, m_NodeList[ 0 ]->Token() ); @@ -1508,6 +1520,12 @@ namespace Compiler if ( IS_STATEMENT( options ) ) EmitByte( QScript::OpCode::OP_POP, chunk ); } + + if ( fn ) + { + // Free temporary function type + FreeTypes( assembler.UnregisterType( varType ) ); + } } else { @@ -1517,17 +1535,19 @@ namespace Compiler // Empty variable EmitByte( QScript::OpCode::OP_LOAD_NULL, chunk ); - if ( !TypeCheck( varType, TYPE_NULL ) ) + if ( !varType->IsAssignable( &Type_t( TYPE_NULL ) ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + - TypeToString( varType ) + ", got: " + TypeToString( TYPE_NULL ), + TypeToString( *varType ) + ", got: " + TypeToString( Type_t( TYPE_NULL ) ), lineNr, colNr, m_NodeList[ 0 ]->Token() ); } + auto unknownType = assembler.RegisterType( QS_NEW Type_t( TYPE_UNKNOWN, TYPE_UNKNOWN ) ); + if ( !isLocal ) { // Global variable - if ( !assembler.AddGlobal( varString, isConst, lineNr, colNr, TYPE_UNKNOWN ) ) + if ( !assembler.AddGlobal( varString, isConst, lineNr, colNr, unknownType ) ) { throw CompilerException( "cp_identifier_already_exists", "Identifier \"" + varString + "\" already exists", m_NodeList[ 0 ]->LineNr(), m_NodeList[ 0 ]->ColNr(), m_NodeList[ 0 ]->Token() ); @@ -1539,8 +1559,10 @@ namespace Compiler else { // Local variable - assembler.AddLocal( varString, isConst, lineNr, colNr, TYPE_UNKNOWN ); + assembler.AddLocal( varString, isConst, lineNr, colNr, unknownType ); } + + FreeTypes( assembler.UnregisterType( unknownType ) ); } break; } @@ -1580,4 +1602,30 @@ namespace Compiler AddDebugSymbol( assembler, start, m_LineNr, m_ColNr, m_Token ); } + + + TypeNode::TypeNode( int lineNr, int colNr, const std::string token, Type_t* type ) + : BaseNode( lineNr, colNr, token, NT_TYPE, NODE_TYPE ) + { + m_Type = DeepCopyType( *type, QS_NEW Type_t ); + } + + void TypeNode::Release() + { + FreeTypes( m_ExprType ); + m_ExprType = NULL; + + FreeTypes( m_Type ); + m_Type = NULL; + } + + void TypeNode::Compile( Assembler& assembler, uint32_t options ) + { + throw CompilerException( "cp_invalid_compilation_node", "Can not compile a type node", m_LineNr, m_ColNr, m_Token ); + } + + const Type_t* TypeNode::GetType() const + { + return m_Type; + } } diff --git a/Library/Compiler/AST/AST.h b/Library/Compiler/AST/AST.h index ae1c6d8..aa3f20c 100644 --- a/Library/Compiler/AST/AST.h +++ b/Library/Compiler/AST/AST.h @@ -12,6 +12,7 @@ namespace Compiler NT_SIMPLE, // Simple node, links to a single subtree (of 1...n items) NT_COMPLEX, // Complex node, links to two (left & right) nodes NT_LIST, // List node, 0...n child nodes + NT_TYPE, // Type node, conveys a Type_t }; enum NodeId @@ -61,6 +62,7 @@ namespace Compiler NODE_RETURN, NODE_SCOPE, NODE_SUB, + NODE_TYPE, NODE_VAR, NODE_WHILE, }; @@ -78,8 +80,17 @@ namespace Compiler struct Argument_t { + Argument_t( const std::string& name, Type_t* type, int lineNr, int colNr ) + { + m_Name = name; + m_Type = type; + m_LineNr = lineNr; + m_ColNr = colNr; + + } + std::string m_Name; - Type_t m_Type; + Type_t* m_Type; int m_LineNr; int m_ColNr; }; @@ -101,7 +112,7 @@ namespace Compiler virtual void Compile( Assembler& assembler, uint32_t options = CO_NONE ) = 0; virtual std::string ToJson( const std::string& ind = "" ) const = 0; - virtual Type_t ExprType( Assembler& assembler ) const { return Compiler::TYPE_NONE; } + virtual const Type_t* ExprType( Assembler& assembler ) = 0; protected: NodeId m_NodeId; @@ -109,22 +120,30 @@ namespace Compiler int m_LineNr; int m_ColNr; std::string m_Token; + + // Node expression type -- Updated and returnted by ExprType() + Type_t* m_ExprType; }; class TermNode : public BaseNode { public: TermNode( int lineNr, int colNr, const std::string token, NodeId id ); + + void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; std::string ToJson( const std::string& ind = "" ) const override; + const Type_t* ExprType( Assembler& assembler ) override; }; class ValueNode : public BaseNode { public: ValueNode( int lineNr, int colNr, const std::string token, NodeId id, const QScript::Value& value ); + + void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - Type_t ExprType( Assembler& assembler ) const override; + const Type_t* ExprType( Assembler& assembler ) override; std::string ToJson( const std::string& ind = "" ) const override; QScript::Value& GetValue() { return m_Value; } @@ -140,11 +159,11 @@ namespace Compiler void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - Type_t ExprType( Assembler& assembler ) const override; + const Type_t* ExprType( Assembler& assembler ) override; std::string ToJson( const std::string& ind = "" ) const override; - const BaseNode* GetLeft() const; - const BaseNode* GetRight() const; + BaseNode* GetLeft(); + BaseNode* GetRight(); private: BaseNode* m_Left; @@ -158,10 +177,10 @@ namespace Compiler void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - Type_t ExprType( Assembler& assembler ) const override; + const Type_t* ExprType( Assembler& assembler ) override; std::string ToJson( const std::string& ind = "" ) const override; - const BaseNode* GetNode() const; + BaseNode* GetNode(); private: BaseNode* m_Node; @@ -174,7 +193,7 @@ namespace Compiler void Release() override; void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; - Type_t ExprType( Assembler& assembler ) const override; + const Type_t* ExprType( Assembler& assembler ) override; const std::vector< BaseNode* >& GetList() const; std::string ToJson( const std::string& ind = "" ) const override; @@ -182,5 +201,20 @@ namespace Compiler std::vector< BaseNode* > m_NodeList; }; - std::vector< Argument_t > ParseArgsList( ListNode* argNode ); + class TypeNode : public BaseNode + { + public: + TypeNode( int lineNr, int colNr, const std::string token, Type_t* type ); + + void Release() override; + void Compile( Assembler& assembler, uint32_t options = CO_NONE ) override; + const Type_t* ExprType( Assembler& assembler ) override; + const Type_t* GetType() const; + std::string ToJson( const std::string& ind = "" ) const override; + + private: + Type_t* m_Type; + }; + + std::vector< Argument_t > ParseArgsList( ListNode* argNode, Assembler& assembler ); } diff --git a/Library/Compiler/AST/ToJson.cpp b/Library/Compiler/AST/ToJson.cpp index 1ab46ac..d24079f 100644 --- a/Library/Compiler/AST/ToJson.cpp +++ b/Library/Compiler/AST/ToJson.cpp @@ -46,6 +46,7 @@ namespace Compiler { NODE_RETURN, "RETURN" }, { NODE_SCOPE, "SCOPE" }, { NODE_SUB, "SUB" }, + { NODE_TYPE, "TYPE" }, { NODE_VAR, "VAR (mutable)" }, { NODE_WHILE, "WHILE" }, }; @@ -109,4 +110,14 @@ namespace Compiler + ind2 + "\"list\": [\n" + listJson + "]\n" + ind + "}"; } + + std::string TypeNode::ToJson( const std::string& ind ) const + { + std::string ind2 = ind + " "; + return ind + "{\n" + + ind2 + "\"type\": \"TypeNode\",\n" + + ind2 + "\"name\": \"" + nodeIdToName[ m_NodeId ] + "\",\n" + + ind2 + "\"typeString\": \"" + TypeToString( *GetType() ) + "\"\n" + + ind + "}"; + } } diff --git a/Library/Compiler/AST/Typing.cpp b/Library/Compiler/AST/Typing.cpp index ab1ec02..d63fbb5 100644 --- a/Library/Compiler/AST/Typing.cpp +++ b/Library/Compiler/AST/Typing.cpp @@ -2,125 +2,26 @@ #include "../../Common/Value.h" #include "../../Common/Chunk.h" #include "../Compiler.h" -#include "Typing.h" #include "AST.h" +#include "Typing.h" + +#define EXPR_TYPE_STATIC( type ) (m_ExprType->m_Bits = type) +#define EXPR_TYPE_COPY( otherType ) DeepCopyType( otherType, m_ExprType ) +#define EXPR_TYPE_FROM_CHILD( child ) DeepCopyType( *child->ExprType( assembler ), m_ExprType ) namespace Compiler { - std::vector< const Type_t* > Type_t::m_Types = {}; - - Type_t* Type_t::AddReturnType( uint32_t bits ) - { - auto type = QS_NEW Type_t( bits ); - m_ReturnType = type; - return type; - } - - Type_t* Type_t::AddArgument( const std::string& name, uint32_t bits ) - { - assert( m_Bits & TYPE_FUNCTION == TYPE_FUNCTION ); - m_ArgTypes.push_back( std::make_pair( name, QS_NEW Type_t( bits ) ) ); - return m_ArgTypes.back().second; - } - - Type_t* Type_t::AddProperty( const std::string& name, uint32_t bits ) - { - assert( m_Bits & TYPE_TABLE == TYPE_TABLE ); - m_PropTypes.push_back( std::make_pair( name, QS_NEW Type_t( bits ) ) ); - return m_PropTypes.back().second; - } - - Type_t* Type_t::AddIndice( uint32_t bits ) - { - assert( m_Bits & TYPE_ARRAY == TYPE_ARRAY ); - m_IndiceTypes.push_back( QS_NEW Type_t( bits ) ); - return m_IndiceTypes.back(); - } - - size_t SaveTypes( const Type_t* types ) - { - if ( !types ) - return NULL; - - Type_t::m_Types.push_back( types ); - return Type_t::m_Types.size() - 1; - } - - const Type_t* LoadTypes( size_t index ) - { - return Type_t::m_Types[ index ]; - } - - void FreeTypes( const Type_t* types ) - { - if ( !types ) - return; - - FreeTypes( types->m_ReturnType ); - - for ( auto arg : types->m_ArgTypes ) - FreeTypes( arg.second ); - - for ( auto prop : types->m_PropTypes ) - FreeTypes( prop.second ); - - for ( auto indice : types->m_IndiceTypes ) - FreeTypes( indice ); - - delete types; - } - - bool TypeCheck( Type_t targetType, Type_t exprType ) - { - if ( targetType.IsUnknown() || exprType.IsUnknown() ) - return true; - - // Strict type checking - return targetType == exprType; - } - - std::string TypeToString( Type_t type ) - { - if ( type.IsUnknown() ) - return "unknown"; - - std::string result = ""; - - std::map< CompileTypeBits, std::string > typeStrings ={ - { TYPE_NULL, "null" }, - { TYPE_NUMBER, "num" }, - { TYPE_BOOL, "bool" }, - { TYPE_TABLE, "Table" }, - { TYPE_ARRAY, "Array" }, - { TYPE_FUNCTION, "function" }, - { TYPE_NATIVE, "native" }, - { TYPE_STRING, "string" }, - { TYPE_NONE, "none" }, - }; - - for ( auto typeString : typeStrings ) - { - if ( type.m_Bits & typeString.first ) - { - if ( result.length() > 0 ) - result += " | " + typeString.second; - else - result = typeString.second; - } - } - - return result.length() > 0 ? result : "not_supported"; - } - - Type_t ResolveReturnType( const ListNode* funcNode, Assembler& assembler ) + void ResolveReturnType( ListNode* funcNode, Assembler& assembler, Type_t* out ) { // Is there an explicitly defined return type? - auto retnTypeNode = static_cast< ValueNode* >( funcNode->GetList()[ 2 ] ); - uint32_t retnType = ( uint32_t ) AS_NUMBER( retnTypeNode->GetValue() ); + const Type_t* returnType = static_cast< TypeNode* >( funcNode->GetList()[ 2 ] )->GetType(); // Type shouldn't be deduced by compiler ? - if ( !( retnType & TYPE_AUTO ) ) - return retnType; + if ( !returnType->IsAuto() ) + { + DeepCopyType( *returnType, out ); + return; + } // Combine all return statement types Type_t returnTypes = Type_t( TYPE_NULL ); @@ -128,15 +29,18 @@ namespace Compiler // Is first return? bool firstReturn = true; - auto argsList = ParseArgsList( static_cast< ListNode* >( funcNode->GetList()[ 0 ] ) ); + auto argsList = ParseArgsList( static_cast< ListNode* >( funcNode->GetList()[ 0 ] ), assembler ); for ( auto arg : argsList ) + { assembler.AddArgument( arg.m_Name, true, arg.m_LineNr, arg.m_ColNr, arg.m_Type ); + FreeTypes( arg.m_Type ); + } - std::function< void( const BaseNode* ) > visitNode; - visitNode = [ &visitNode, &returnTypes, &firstReturn, &assembler ]( const BaseNode* node ) -> void + std::function< void( BaseNode* ) > visitNode; + visitNode = [ &visitNode, &returnTypes, &firstReturn, &assembler ]( BaseNode* node ) -> void { - if ( !node || returnTypes.m_Bits == TYPE_UNKNOWN ) + if ( !node || returnTypes.IsUnknown() ) return; switch ( node->Type() ) @@ -153,7 +57,7 @@ namespace Compiler } case NT_SIMPLE: { - auto simple = static_cast< const SimpleNode* >( node ); + auto simple = static_cast< SimpleNode* >( node ); if ( simple->Id() == NODE_RETURN ) { @@ -166,10 +70,10 @@ namespace Compiler auto returnExpressionType = simple->GetNode()->ExprType( assembler ); - if ( returnExpressionType.m_Bits == TYPE_UNKNOWN ) + if ( returnExpressionType->IsUnknown() ) returnTypes.m_Bits = TYPE_UNKNOWN; else - returnTypes.m_Bits |= returnExpressionType.m_Bits; + returnTypes.Join( returnExpressionType ); // TODO: Error if type join fails } else { @@ -182,7 +86,7 @@ namespace Compiler break; case NT_COMPLEX: { - auto complex = static_cast< const ComplexNode* >( node ); + auto complex = static_cast< ComplexNode* >( node ); visitNode( complex->GetLeft() ); visitNode( complex->GetRight() ); @@ -206,10 +110,23 @@ namespace Compiler visitNode( funcNode ); assembler.ClearArguments(); - return returnTypes; + + DeepCopyType( returnTypes, out ); } - Type_t ValueNode::ExprType( Assembler& assembler ) const + const Type_t* TermNode::ExprType( Assembler& assembler ) + { + switch ( m_NodeId ) + { + case NODE_RETURN: EXPR_TYPE_STATIC( TYPE_NULL ); break; + default: + throw CompilerException( "cp_invalid_term_node", "Unknown term node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); + } + + return m_ExprType; + } + + const Type_t* ValueNode::ExprType( Assembler& assembler ) { switch ( m_NodeId ) { @@ -220,71 +137,82 @@ namespace Compiler Variable_t varInfo; if ( assembler.FindArgument( name, &varInfo ) ) - return varInfo.m_Type; - - if ( assembler.FindLocal( name, &nameIndex, &varInfo ) ) - return varInfo.m_Type; - - if ( assembler.FindUpvalue( name, &nameIndex, &varInfo ) ) - return varInfo.m_Type; - - if ( assembler.FindGlobal( name, &varInfo ) ) - return varInfo.m_Type; - - return TYPE_NONE; + EXPR_TYPE_COPY( *varInfo.m_Type ); + else if ( assembler.FindLocal( name, &nameIndex, &varInfo ) ) + EXPR_TYPE_COPY( *varInfo.m_Type ); + else if ( assembler.FindUpvalue( name, &nameIndex, &varInfo ) ) + EXPR_TYPE_COPY( *varInfo.m_Type ); + else if ( assembler.FindGlobal( name, &varInfo ) ) + EXPR_TYPE_COPY( *varInfo.m_Type ); + else + EXPR_TYPE_STATIC( TYPE_NONE ); + + break; } case NODE_CONSTANT: { - if ( IS_NUMBER( m_Value ) ) return Type_t( TYPE_NUMBER ); - else if ( IS_NULL( m_Value ) ) return Type_t( TYPE_NULL ); - else if ( IS_BOOL( m_Value ) ) return Type_t( TYPE_BOOL ); + if ( IS_NUMBER( m_Value ) ) EXPR_TYPE_STATIC( TYPE_NUMBER ); + else if ( IS_NULL( m_Value ) ) EXPR_TYPE_STATIC( TYPE_NULL ); + else if ( IS_BOOL( m_Value ) ) EXPR_TYPE_STATIC( TYPE_BOOL ); else if ( IS_OBJECT( m_Value ) ) { switch ( AS_OBJECT( m_Value )->m_Type ) { - case QScript::OT_TABLE: return Type_t( TYPE_TABLE ); - case QScript::OT_CLOSURE: return Type_t( TYPE_CLOSURE ); - case QScript::OT_FUNCTION: return Type_t( TYPE_FUNCTION ); - case QScript::OT_NATIVE: return Type_t( TYPE_NATIVE ); - case QScript::OT_STRING: return Type_t( TYPE_STRING ); - case QScript::OT_UPVALUE: return Type_t( TYPE_UPVALUE ); + case QScript::OT_TABLE: EXPR_TYPE_STATIC( TYPE_TABLE ); break; + case QScript::OT_CLOSURE: EXPR_TYPE_STATIC( TYPE_CLOSURE ); break; + case QScript::OT_FUNCTION: EXPR_TYPE_STATIC( TYPE_FUNCTION ); break; + case QScript::OT_NATIVE: EXPR_TYPE_STATIC( TYPE_NATIVE ); break; + case QScript::OT_STRING: EXPR_TYPE_STATIC( TYPE_STRING ); break; + case QScript::OT_UPVALUE: EXPR_TYPE_STATIC( TYPE_UPVALUE ); break; default: break; } } - return Type_t( TYPE_UNKNOWN ); + else + { + EXPR_TYPE_STATIC( TYPE_UNKNOWN ); + } + + break; } default: throw CompilerException( "cp_invalid_value_node", "Unknown value node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); } + + return m_ExprType; } - Type_t ComplexNode::ExprType( Assembler& assembler ) const + const Type_t* ComplexNode::ExprType( Assembler& assembler ) { switch ( m_NodeId ) { case NODE_ACCESS_PROP: { // TODO: Resolve table property types compile-time - return Type_t( TYPE_UNKNOWN ); + EXPR_TYPE_STATIC( TYPE_UNKNOWN ); + break; } case NODE_ACCESS_ARRAY: { // TODO: Compile-time arrays? - return Type_t( TYPE_UNKNOWN ); + EXPR_TYPE_STATIC( TYPE_UNKNOWN ); + break; } - case NODE_ASSIGN: return m_Right->ExprType( assembler ); - case NODE_ASSIGNADD: return m_Right->ExprType( assembler ); - case NODE_ASSIGNDIV: return Type_t( TYPE_NUMBER ); - case NODE_ASSIGNMOD: return Type_t( TYPE_NUMBER ); - case NODE_ASSIGNMUL: return Type_t( TYPE_NUMBER ); - case NODE_ASSIGNSUB: return Type_t( TYPE_NUMBER ); + case NODE_ASSIGN: EXPR_TYPE_FROM_CHILD( m_Right ); break; + case NODE_ASSIGNADD: EXPR_TYPE_FROM_CHILD( m_Right ); break; + case NODE_ASSIGNDIV: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_ASSIGNMOD: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_ASSIGNMUL: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_ASSIGNSUB: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; case NODE_CALL: { // Return type switch ( m_Left->Id() ) { case NODE_FUNC: - return ResolveReturnType( static_cast< ListNode* >( m_Left ), assembler ); + { + ResolveReturnType( static_cast< ListNode* >( m_Left ), assembler, m_ExprType ); + break; + } case NODE_NAME: { auto nameValue = static_cast< ValueNode* >( m_Left )->GetValue(); @@ -293,113 +221,149 @@ namespace Compiler uint32_t nameIndex; Variable_t varInfo; - if ( assembler.FindLocal( name, &nameIndex, &varInfo ) ) - return varInfo.m_Type.m_ReturnType ? *varInfo.m_Type.m_ReturnType : Type_t( TYPE_NONE ); - - if ( assembler.FindUpvalue( name, &nameIndex, &varInfo ) ) - return varInfo.m_Type.m_ReturnType ? *varInfo.m_Type.m_ReturnType : Type_t( TYPE_NONE ); - - if ( assembler.FindGlobal( name, &varInfo ) ) - return varInfo.m_Type.m_ReturnType ? *varInfo.m_Type.m_ReturnType : Type_t( TYPE_NONE ); + if ( assembler.FindLocal( name, &nameIndex, &varInfo ) + || assembler.FindUpvalue( name, &nameIndex, &varInfo ) + || assembler.FindGlobal( name, &varInfo ) ) + { + // Identifier has return type? + if ( varInfo.m_Type->m_ReturnType ) + EXPR_TYPE_COPY( *varInfo.m_Type->m_ReturnType ); + else if ( varInfo.m_Type->IsUnknown() ) + EXPR_TYPE_STATIC( TYPE_UNKNOWN ); + else + EXPR_TYPE_STATIC( TYPE_NONE ); + } + else + { + // Identifier not found + EXPR_TYPE_STATIC( TYPE_NONE ); + } break; } default: + EXPR_TYPE_STATIC( TYPE_UNKNOWN ); break; } - return TYPE_UNKNOWN; + break; + } + case NODE_AND: + { + EXPR_TYPE_FROM_CHILD( m_Left ); + m_ExprType->Join( m_Right->ExprType( assembler ) ); + break; } - case NODE_AND: return m_Left->ExprType( assembler ) | m_Right->ExprType( assembler ); - case NODE_OR: return m_Left->ExprType( assembler ) | m_Right->ExprType( assembler ); - case NODE_DEC: return Type_t( TYPE_NUMBER ); - case NODE_INC: return Type_t( TYPE_NUMBER ); + case NODE_OR: + { + EXPR_TYPE_FROM_CHILD( m_Left ); + m_ExprType->Join( m_Right->ExprType( assembler ) ); + break; + } + case NODE_DEC: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_INC: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; case NODE_ADD: { auto leftType = m_Left->ExprType( assembler ); auto rightType = m_Right->ExprType( assembler ); - if ( ( leftType & TYPE_STRING ) || ( rightType & TYPE_STRING ) ) - return TYPE_STRING; - - if ( leftType.IsUnknown() ) - return leftType; + if ( Type_t( TYPE_STRING ).DeepEquals( leftType ) ) + EXPR_TYPE_STATIC( TYPE_STRING ); + else if ( Type_t( TYPE_STRING ).DeepEquals( rightType ) ) + EXPR_TYPE_STATIC( TYPE_STRING ); + else if ( leftType->IsUnknown() || rightType->IsUnknown() ) + EXPR_TYPE_STATIC( TYPE_UNKNOWN ); + else + EXPR_TYPE_STATIC( TYPE_NUMBER ); - if ( rightType.IsUnknown() ) - return rightType; - - return TYPE_NUMBER; + break; } - case NODE_SUB: return Type_t( TYPE_NUMBER ); - case NODE_MUL: return Type_t( TYPE_NUMBER ); - case NODE_DIV: return Type_t( TYPE_NUMBER ); - case NODE_MOD: return Type_t( TYPE_NUMBER ); - case NODE_POW: return Type_t( TYPE_NUMBER ); - case NODE_EQUALS: return Type_t( TYPE_BOOL ); - case NODE_NOTEQUALS: return Type_t( TYPE_BOOL ); - case NODE_GREATERTHAN: return Type_t( TYPE_BOOL ); - case NODE_GREATEREQUAL: return Type_t( TYPE_BOOL ); - case NODE_LESSTHAN: return Type_t( TYPE_BOOL ); - case NODE_LESSEQUAL: return Type_t( TYPE_BOOL ); + case NODE_SUB: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_MUL: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_DIV: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_MOD: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_POW: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; + case NODE_EQUALS: EXPR_TYPE_STATIC( TYPE_BOOL ); break; + case NODE_NOTEQUALS: EXPR_TYPE_STATIC( TYPE_BOOL ); break; + case NODE_GREATERTHAN: EXPR_TYPE_STATIC( TYPE_BOOL ); break; + case NODE_GREATEREQUAL: EXPR_TYPE_STATIC( TYPE_BOOL ); break; + case NODE_LESSTHAN: EXPR_TYPE_STATIC( TYPE_BOOL ); break; + case NODE_LESSEQUAL: EXPR_TYPE_STATIC( TYPE_BOOL ); break; default: throw CompilerException( "cp_invalid_complex_node", "Unknown complex node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); } + + return m_ExprType; } - Type_t SimpleNode::ExprType( Assembler& assembler ) const + const Type_t* SimpleNode::ExprType( Assembler& assembler ) { switch ( m_NodeId ) { - case NODE_IMPORT: return Type_t( TYPE_NONE ); - case NODE_RETURN: return m_Node->ExprType( assembler ); - case NODE_NOT: return Type_t( TYPE_BOOL ); - case NODE_NEG: return Type_t( TYPE_NUMBER ); + case NODE_IMPORT: EXPR_TYPE_STATIC( TYPE_NONE ); break; + case NODE_RETURN: EXPR_TYPE_FROM_CHILD( m_Node ); break; + case NODE_NOT: EXPR_TYPE_STATIC( TYPE_BOOL ); break; + case NODE_NEG: EXPR_TYPE_STATIC( TYPE_NUMBER ); break; default: throw CompilerException( "cp_invalid_simple_node", "Unknown simple node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); } + + return m_ExprType; } - Type_t ListNode::ExprType( Assembler& assembler ) const + const Type_t* ListNode::ExprType( Assembler& assembler ) { switch ( m_NodeId ) { - case NODE_TABLE: return Type_t( TYPE_TABLE ); - case NODE_ARRAY: return Type_t( TYPE_ARRAY ); - case NODE_DO: return Type_t( TYPE_NONE ); - case NODE_FOR: return Type_t( TYPE_NONE ); - case NODE_FUNC: return Type_t( TYPE_FUNCTION ); - case NODE_IF: return Type_t( TYPE_NONE ); - case NODE_SCOPE: return Type_t( TYPE_NONE ); - case NODE_WHILE: return Type_t( TYPE_NONE ); + case NODE_TABLE: EXPR_TYPE_STATIC( TYPE_TABLE ); break; + case NODE_ARRAY: EXPR_TYPE_STATIC( TYPE_ARRAY ); break; + case NODE_FUNC: EXPR_TYPE_STATIC( TYPE_FUNCTION ); break; case NODE_INLINE_IF: { - return m_NodeList[ 1 ]->ExprType( assembler ) | m_NodeList[ 2 ]->ExprType( assembler ); + EXPR_TYPE_FROM_CHILD( m_NodeList[ 1 ] ); + m_ExprType->Join( m_NodeList[ 2 ]->ExprType( assembler ) ); + break; } case NODE_CONSTVAR: { - auto& varTypeValue = static_cast< ValueNode* >( m_NodeList[ 2 ] )->GetValue(); - auto assignedType = ( uint32_t ) AS_NUMBER( varTypeValue ); + const Type_t* varType = static_cast< TypeNode* >( m_NodeList[ 2 ] )->GetType(); - if ( assignedType != TYPE_UNKNOWN && !( assignedType & TYPE_AUTO ) ) - return Type_t( assignedType ); + if ( !varType->IsAuto() ) + EXPR_TYPE_COPY( *varType ); // "const num x = ..." + else if ( !m_NodeList[ 1 ] ) + EXPR_TYPE_STATIC( TYPE_NULL ); // "const x;", "const auto x;" - if ( !m_NodeList[ 1 ] ) - return Type_t( TYPE_UNKNOWN ); - - return m_NodeList[ 1 ]->ExprType( assembler ); + // "const auto x = ..." + EXPR_TYPE_FROM_CHILD( m_NodeList[ 1 ] ); + break; } case NODE_VAR: { - auto& varTypeValue = static_cast< ValueNode* >( m_NodeList[ 2 ] )->GetValue(); - auto type = ( uint32_t ) AS_NUMBER( varTypeValue ); + const Type_t* varType = static_cast< TypeNode* >( m_NodeList[ 2 ] )->GetType(); - if ( ( type & TYPE_AUTO ) && m_NodeList[ 1 ] ) - return m_NodeList[ 1 ]->ExprType( assembler ); + if ( varType->IsAuto() && m_NodeList[ 1 ] ) + EXPR_TYPE_FROM_CHILD( m_NodeList[ 1 ] ); + else + EXPR_TYPE_COPY( *varType ); - return Type_t( type ); + break; } + case NODE_DO: + case NODE_FOR: + case NODE_IF: + case NODE_SCOPE: + case NODE_WHILE: + EXPR_TYPE_STATIC( TYPE_NONE ); + break; default: throw CompilerException( "cp_invalid_list_node", "Unknown list node: " + std::to_string( m_NodeId ), m_LineNr, m_ColNr, m_Token ); } + + return m_ExprType; + } + + const Type_t* TypeNode::ExprType( Assembler& assembler ) + { + throw CompilerException( "cp_invalid_type_node", "Can not get type of a type node. Call GetType() instead", m_LineNr, m_ColNr, m_Token ); } } diff --git a/Library/Compiler/AST/Typing.h b/Library/Compiler/AST/Typing.h index 7c373bc..0fc3eaa 100644 --- a/Library/Compiler/AST/Typing.h +++ b/Library/Compiler/AST/Typing.h @@ -1,64 +1,12 @@ #pragma once +// Include Type_t +#include "../Types.h" + namespace Compiler { - enum CompileTypeBits : uint32_t - { - // Primitives - TYPE_UNKNOWN = ( 0 << 0 ), - TYPE_NULL = ( 1 << 0 ), - TYPE_NUMBER = ( 1 << 1 ), - TYPE_BOOL = ( 1 << 2 ), - - // Objects - TYPE_TABLE = ( 1 << 3 ), - TYPE_CLOSURE = ( 1 << 4 ), - TYPE_FUNCTION = ( 1 << 5 ), - TYPE_INSTANCE = ( 1 << 6 ), - TYPE_NATIVE = ( 1 << 7 ), - TYPE_STRING = ( 1 << 8 ), - TYPE_UPVALUE = ( 1 << 9 ), - TYPE_ARRAY = ( 1 << 10 ), - - // No type (statements) - TYPE_NONE = ( 1 << 11 ), - - // Hint compiler to deduce type - TYPE_AUTO = ( 1 << 12 ), - }; - - struct Type_t - { - Type_t( uint32_t bits ) : m_Bits( bits ) - { - m_ReturnType = NULL; - } - - Type_t* AddReturnType( uint32_t bits ); - Type_t* AddArgument( const std::string& name, uint32_t bits ); - Type_t* AddProperty( const std::string& name, uint32_t bits ); - Type_t* AddIndice( uint32_t bits ); - - Type_t operator|( const Type_t& other ) const { return Type_t( m_Bits | other.m_Bits ); } - uint32_t operator&( const Type_t& other ) const { return m_Bits & other.m_Bits; } - uint32_t operator&( uint32_t bits ) const { return m_Bits & bits; } - bool operator==( const Type_t& other ) const { return m_Bits == other.m_Bits; } - - bool IsUnknown() const { return m_Bits == TYPE_UNKNOWN; } - - uint32_t m_Bits; - Type_t* m_ReturnType; // Function returns - - std::vector< std::pair< std::string, Type_t* > > m_ArgTypes; // Function arguments - std::vector< std::pair< std::string, Type_t* > > m_PropTypes; // Table props - std::vector< Type_t* > m_IndiceTypes; // Array indices - - static std::vector< const Type_t* > m_Types; - }; - - size_t SaveTypes( const Type_t* types ); - const Type_t* LoadTypes( size_t index ); - void FreeTypes( const Type_t* types ); + class Assembler; + class ListNode; - Type_t ResolveReturnType( const ListNode* funcNode, Assembler& assembler ); + void ResolveReturnType( ListNode* funcNode, Assembler& assembler, Type_t* out ); } diff --git a/Library/Compiler/Compiler.cpp b/Library/Compiler/Compiler.cpp index 469ca54..72fb6fd 100644 --- a/Library/Compiler/Compiler.cpp +++ b/Library/Compiler/Compiler.cpp @@ -4,7 +4,7 @@ #include "Instructions.h" #include "Compiler.h" -#include "Typing.h" +#include "Types.h" #define BEGIN_COMPILER \ Object::AllocateString = &Compiler::AllocateString; \ @@ -461,7 +461,7 @@ namespace Compiler void GarbageCollect( const std::vector< Compiler::BaseNode* >& nodes ) { std::vector< QScript::Value > values; - std::vector< const Compiler::BaseNode* > queue; + std::vector< Compiler::BaseNode* > queue; for ( auto node : nodes ) queue.push_back( node ); @@ -484,12 +484,12 @@ namespace Compiler break; } case NT_SIMPLE: - queue.push_back( static_cast< const SimpleNode* >( node )->GetNode() ); + queue.push_back( static_cast< SimpleNode* >( node )->GetNode() ); break; case NT_COMPLEX: { - queue.push_back( static_cast< const ComplexNode* >( node )->GetLeft() ); - queue.push_back( static_cast< const ComplexNode* >( node )->GetRight() ); + queue.push_back( static_cast< ComplexNode* >( node )->GetLeft() ); + queue.push_back( static_cast< ComplexNode* >( node )->GetRight() ); break; } case NT_LIST: @@ -536,9 +536,9 @@ namespace Compiler { // Fill out globals for REPL for ( auto identifier : config.m_Globals ) - AddGlobal( identifier, false, -1, -1, Type_t( TYPE_UNKNOWN ), NULL ); + AddGlobal( identifier, false, -1, -1, &Type_t( TYPE_UNKNOWN ), NULL ); - CreateFunction( "
", true, Type_t( TYPE_UNKNOWN ), true, true, chunk ); + CreateFunction( "
", true, &Type_t( TYPE_UNKNOWN ), true, true, chunk ); } void Assembler::Release() @@ -546,6 +546,9 @@ namespace Compiler // Called when a compilation error occurred and all previously compiled // materials need to be freed + for ( auto type : m_Types ) + FreeTypes( type ); + for ( auto context : m_Functions ) { delete context.m_Func->GetChunk(); @@ -560,6 +563,10 @@ namespace Compiler throw Exception( "cp_unescaped_function", "Abort: Compiler was left with unfinished functions" ); delete CurrentStack(); + + for ( auto type : m_Types ) + FreeTypes( type ); + m_Compiled.push_back( m_Functions[ 0 ].m_Func ); m_Functions.pop_back(); @@ -591,10 +598,10 @@ namespace Compiler return m_Functions.back().m_Stack; } - QScript::FunctionObject* Assembler::CreateFunction( const std::string& name, bool isConst, Type_t type, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ) + QScript::FunctionObject* Assembler::CreateFunction( const std::string& name, bool isConst, const Type_t* type, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ) { auto function = QS_NEW QScript::FunctionObject( name, chunk ); - auto context = FunctionContext_t{ function, QS_NEW Assembler::Stack_t(), type }; + auto context = FunctionContext_t{ function, QS_NEW Assembler::Stack_t(), DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ) }; m_Functions.push_back( context ); @@ -624,14 +631,16 @@ namespace Compiler // Finished compiling m_Compiled.push_back( function->m_Func ); - // Free compile-time stack from memory + // Free compile-time stack & types from memory + // FreeTypes( CurrentContext()->m_Type ); delete CurrentStack(); + m_Functions.pop_back(); } - void Assembler::AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type ) + void Assembler::AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, const Type_t* type ) { - auto variable = Variable_t{ name, isConstant, type, NULL }; + auto variable = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ) ); if ( m_Config.m_IdentifierCb ) m_Config.m_IdentifierCb( lineNr, colNr, variable, "Argument" ); @@ -639,11 +648,11 @@ namespace Compiler m_FunctionArgs.push_back( variable ); } - uint32_t Assembler::AddLocal( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type, QScript::FunctionObject* fn ) + uint32_t Assembler::AddLocal( const std::string& name, bool isConstant, int lineNr, int colNr, const Type_t* type, QScript::FunctionObject* fn ) { auto stack = CurrentStack(); - auto variable = Variable_t{ name, isConstant, type, fn }; + auto variable = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ), fn ); if ( m_Config.m_IdentifierCb ) m_Config.m_IdentifierCb( lineNr, colNr, variable, "Local" ); @@ -720,12 +729,12 @@ namespace Compiler return false; } - bool Assembler::AddGlobal( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type, QScript::FunctionObject* fn ) + bool Assembler::AddGlobal( const std::string& name, bool isConstant, int lineNr, int colNr, const Type_t* type, QScript::FunctionObject* fn ) { if ( m_Globals.find( name ) != m_Globals.end() ) return false; - Variable_t global = Variable_t{ name, isConstant, type, fn }; + Variable_t global = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ), fn ); m_Globals.insert( std::make_pair( name, global ) ); if ( m_Config.m_IdentifierCb ) @@ -809,12 +818,42 @@ namespace Compiler else EmitByte( QScript::OpCode::OP_CLOSE_UPVALUE, CurrentChunk() ); + // Free types + // FreeTypes( local.m_Var.m_Type ); + stack->m_Locals.erase( stack->m_Locals.begin() + i ); } --stack->m_CurrentDepth; } + Type_t* Assembler::RegisterType( Type_t* type ) + { + m_Types.push_back( type ); + return type; + } + + const Type_t* Assembler::UnregisterType( const Type_t* type ) + { + if ( !type ) + return NULL; + + UnregisterType( type->m_ReturnType ); + + for ( auto arg : type->m_ArgTypes ) + UnregisterType( arg.second ); + + for ( auto prop : type->m_PropTypes ) + UnregisterType( prop.second ); + + for ( auto indice : type->m_IndiceTypes ) + UnregisterType( indice ); + + m_Types.erase( std::remove( m_Types.begin(), m_Types.end(), type ), m_Types.end() ); + + return type; + } + const QScript::Config_t& Assembler::Config() const { return m_Config; @@ -822,6 +861,9 @@ namespace Compiler void Assembler::ClearArguments() { + //for ( auto arg : m_FunctionArgs ) + // FreeTypes( arg.m_Type ); + m_FunctionArgs.clear(); } } diff --git a/Library/Compiler/Compiler.h b/Library/Compiler/Compiler.h index cf499cf..9006a15 100644 --- a/Library/Compiler/Compiler.h +++ b/Library/Compiler/Compiler.h @@ -2,15 +2,13 @@ #include "Tokens.h" #include "AST/AST.h" -#include "Typing.h" +#include "Types.h" struct VM_t; class Object; namespace Compiler { - struct Type_t; - std::vector< Token_t > Lexer( const std::string& source ); std::vector< BaseNode* > GenerateIR( const std::vector< Token_t >& tokens ); // std::vector< BaseNode* > OptimizeIR( std::vector< BaseNode* > nodes ); @@ -34,15 +32,25 @@ namespace Compiler struct Variable_t { - Variable_t() : m_Type( TYPE_UNKNOWN ) + Variable_t() + { + m_Name = ""; + m_IsConst = false; + m_Type = NULL; + m_Function = NULL; + } + + Variable_t( const std::string& name, bool isConst, Type_t* type, QScript::FunctionObject* func = NULL ) { - m_IsConst = false; - m_Function = NULL; + m_Name = name; + m_IsConst = isConst; + m_Type = type; + m_Function = func; } std::string m_Name; bool m_IsConst; - Type_t m_Type; + Type_t* m_Type; QScript::FunctionObject* m_Function; }; @@ -77,23 +85,23 @@ namespace Compiler { QScript::FunctionObject* m_Func; Stack_t* m_Stack; - Type_t m_Type; + Type_t* m_Type; std::vector< Upvalue_t > m_Upvalues; }; Assembler( QScript::Chunk_t* chunk, const QScript::Config_t& config ); - void AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, Type_t type ); + void AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, const Type_t* type ); bool AddGlobal( const std::string& name, bool isConstant, int lineNr, int colNr, - Type_t type, QScript::FunctionObject* fn = NULL ); + const Type_t* type, QScript::FunctionObject* fn = NULL ); uint32_t AddLocal( const std::string& name, bool isConstant, int lineNr, int colNr, - Type_t type, QScript::FunctionObject* fn = NULL ); + const Type_t* type, QScript::FunctionObject* fn = NULL ); uint32_t AddUpvalue( FunctionContext_t* context, uint32_t index, bool isLocal, int lineNr, int colNr, Variable_t* varInfo ); void ClearArguments(); const QScript::Config_t& Config() const; - QScript::FunctionObject* CreateFunction( const std::string& name, bool isConst, Type_t type, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ); + QScript::FunctionObject* CreateFunction( const std::string& name, bool isConst, const Type_t* type, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ); const std::vector< Variable_t >& CurrentArguments(); QScript::Chunk_t* CurrentChunk(); const FunctionContext_t* CurrentContext(); @@ -110,9 +118,11 @@ namespace Compiler bool IsTopLevel(); void PopScope(); void PushScope(); + Type_t* RegisterType( Type_t* type ); void Release(); bool RequestUpvalue( const std::string name, uint32_t* out, int lineNr, int colNr, Variable_t* varInfo ); int StackDepth(); + const Type_t* UnregisterType( const Type_t* type ); private: std::vector< Variable_t > m_FunctionArgs; @@ -121,5 +131,6 @@ namespace Compiler std::vector< QScript::FunctionObject* > m_Compiled; std::map< std::string, Variable_t > m_Globals; + std::vector< Type_t* > m_Types; }; }; diff --git a/Library/Compiler/IRGenerator.cpp b/Library/Compiler/IRGenerator.cpp index 86c00be..3ec74a7 100644 --- a/Library/Compiler/IRGenerator.cpp +++ b/Library/Compiler/IRGenerator.cpp @@ -3,7 +3,7 @@ #include "Compiler.h" #include "Instructions.h" -#include "Typing.h" +#include "Types.h" #include "IR.h" namespace Compiler @@ -18,23 +18,26 @@ namespace Compiler return IS_STRING( static_cast< ValueNode* >( node )->GetValue() ); } - CompileTypeBits ResolveTypeDef( ParserState& parserState ) + bool ResolveTypeDef( ParserState& parserState, Type_t* out ) { std::map< Token, CompileTypeBits > typeMap = { - { TOK_AUTO, TYPE_AUTO }, - { TOK_STRING, TYPE_STRING }, - { TOK_BOOL, TYPE_BOOL }, - { TOK_NUMBER, TYPE_NUMBER }, - { TOK_VAR, TYPE_UNKNOWN }, + { TOK_AUTO, TYPE_AUTO }, + { TOK_STRING, TYPE_STRING }, + { TOK_BOOL, TYPE_BOOL }, + { TOK_NUMBER, TYPE_NUMBER }, + { TOK_VAR, TYPE_UNKNOWN }, // TODO: remove? }; for ( auto type : typeMap ) { if ( parserState.MatchCurrent( type.first ) ) - return type.second; + { + out->m_Bits = type.second; + return true; + } } - return TYPE_NONE; + return false; } ListNode* ParseFunction( ParserState& parserState, const IrBuilder_t& irBuilder, NextExpressionFn nextExpression ) @@ -74,11 +77,13 @@ namespace Compiler if ( !parserState.MatchCurrent( TOK_PAREN_RIGHT ) ) { do { - auto typeDef = ResolveTypeDef( parserState ); + Type_t type( TYPE_NONE ); + + auto hasType = ResolveTypeDef( parserState, &type ); auto argName = nextExpression( BP_VAR ); - if ( typeDef == TYPE_NONE ) - typeDef = TYPE_UNKNOWN; // no type specified, use unknown + if ( !hasType ) + type.m_Bits = TYPE_UNKNOWN; // no type specified, use unknown if ( !IsString( argName ) ) { @@ -92,10 +97,10 @@ namespace Compiler TYPE_NUMBER }; - if ( std::find( validTypes.begin(), validTypes.end(), typeDef ) != validTypes.end() ) + if ( std::find( validTypes.begin(), validTypes.end(), type.m_Bits ) != validTypes.end() ) { - auto varTypeNode = parserState.AllocateNode< ValueNode >( irBuilder.m_Token.m_LineNr, irBuilder.m_Token.m_ColNr, - irBuilder.m_Token.m_String, NODE_CONSTANT, MAKE_NUMBER( typeDef ) ); + auto varTypeNode = parserState.AllocateNode< TypeNode >( irBuilder.m_Token.m_LineNr, + irBuilder.m_Token.m_ColNr, irBuilder.m_Token.m_String, &type ); argsList.push_back( parserState.AllocateNode< ListNode >( irBuilder.m_Token.m_LineNr, irBuilder.m_Token.m_ColNr, irBuilder.m_Token.m_String, NODE_VAR, @@ -114,14 +119,14 @@ namespace Compiler parserState.Expect( TOK_ARROW, "Expected \"->\" after \"var = (...)\", got: \"" + parserState.CurrentBuilder()->m_Token.m_String + "\"" ); // Check for explicit return type - uint32_t retnType = ResolveTypeDef( parserState ); + Type_t type( TYPE_NONE ); - if ( retnType == TYPE_NONE ) - retnType = TYPE_UNKNOWN; // use auto-deduction + if ( !ResolveTypeDef( parserState, &type ) ) + type.m_Bits = TYPE_UNKNOWN; // use unknown // Append type information as a value node - auto retnTypeNode = parserState.AllocateNode< ValueNode >( irBuilder.m_Token.m_LineNr, irBuilder.m_Token.m_ColNr, - irBuilder.m_Token.m_String, NODE_CONSTANT, MAKE_NUMBER( retnType ) ); + auto retnTypeNode = parserState.AllocateNode< TypeNode >( irBuilder.m_Token.m_LineNr, + irBuilder.m_Token.m_ColNr, irBuilder.m_Token.m_String, &type ); auto body = parserState.ToScope( nextExpression( irBuilder.m_Token.m_LBP ) ); @@ -167,13 +172,14 @@ namespace Compiler if ( parserState.CurrentBuilder()->m_Token.m_Id == TOK_ARRAY ) return nextExpression( BP_NONE ); - auto fieldType = ResolveTypeDef( parserState ); + Type_t type( TYPE_NONE ); + auto hasType = ResolveTypeDef( parserState, &type ); - if ( !bMatchConst && fieldType == TYPE_NONE ) + if ( !bMatchConst && !hasType ) return NULL; - auto fieldTypeNode = parserState.AllocateNode< ValueNode >( irBuilder.m_Token.m_LineNr, irBuilder.m_Token.m_ColNr, - irBuilder.m_Token.m_String, NODE_CONSTANT, MAKE_NUMBER( fieldType ) ); + auto fieldTypeNode = parserState.AllocateNode< TypeNode >( irBuilder.m_Token.m_LineNr, + irBuilder.m_Token.m_ColNr, irBuilder.m_Token.m_String, &type ); auto fieldNameNode = nextExpression( BP_VAR ); @@ -407,28 +413,25 @@ namespace Compiler { builder->m_Nud = [ &parserState, &nextExpression ]( const IrBuilder_t& irBuilder ) { - auto varType = TYPE_UNKNOWN; + Type_t type( TYPE_UNKNOWN ); switch ( irBuilder.m_Token.m_Id ) { case TOK_AUTO: - varType = TYPE_AUTO; + type.m_Bits = TYPE_AUTO; break; case TOK_BOOL: - varType = TYPE_BOOL; + type.m_Bits = TYPE_BOOL; break; case TOK_STRING: - varType = TYPE_STRING; + type.m_Bits = TYPE_STRING; break; case TOK_NUMBER: - varType = TYPE_NUMBER; + type.m_Bits = TYPE_NUMBER; break; case TOK_CONST: { - varType = ResolveTypeDef( parserState ); - - if ( varType == TYPE_NONE ) - varType = TYPE_UNKNOWN; + ResolveTypeDef( parserState, &type ); break; } case TOK_VAR: @@ -445,8 +448,8 @@ namespace Compiler } // Append type information as a value node - auto varTypeNode = parserState.AllocateNode< ValueNode >( irBuilder.m_Token.m_LineNr, irBuilder.m_Token.m_ColNr, - irBuilder.m_Token.m_String, NODE_CONSTANT, MAKE_NUMBER( varType ) ); + auto varTypeNode = parserState.AllocateNode< TypeNode >( irBuilder.m_Token.m_LineNr, + irBuilder.m_Token.m_ColNr, irBuilder.m_Token.m_String, &type ); if ( parserState.MatchCurrent( TOK_EQUALS ) ) { diff --git a/Library/Compiler/Types.cpp b/Library/Compiler/Types.cpp new file mode 100644 index 0000000..642a9c4 --- /dev/null +++ b/Library/Compiler/Types.cpp @@ -0,0 +1,247 @@ +#include "QLibPCH.h" +#include "Types.h" + +namespace Compiler +{ + bool FunctionTypeEqualStrict( const Type_t* a, const Type_t* b ) + { + // Are return types the same? + if ( !a->m_ReturnType->DeepEquals( b->m_ReturnType ) ) + return false; + + // Same number of arguments? + if ( a->m_ArgTypes.size() != b->m_ArgTypes.size() ) + return false; + + // Same argument types? + for ( size_t i = 0; i < a->m_ArgTypes.size(); ++i ) + { + auto arg = a->m_ArgTypes[ i ].second; + auto exprArg = b->m_ArgTypes[ i ].second; + + if ( !arg->DeepEquals( exprArg ) ) + return false; + } + + return true; + } + + bool TableTypeEqualStrict( const Type_t* a, const Type_t* b ) + { + // Same number of properties? + if ( a->m_PropTypes.size() != b->m_PropTypes.size() ) + return false; + + // Same property names & types? + for ( auto prop : a->m_PropTypes ) + { + auto exprProp = std::find_if( b->m_PropTypes.begin(), b->m_PropTypes.end(), [ &prop ]( const NamedType_t& type ) { + return type.first == prop.first; + } ); + + // Was the property found? + if ( exprProp == b->m_PropTypes.end() ) + return false; + + // Property types differ? + if ( !prop.second->DeepEquals( exprProp->second ) ) + return false; + } + + return true; + } + + bool ArrayTypeEqualStrict( const Type_t* a, const Type_t* b ) + { + // Same array indice types? + for ( size_t i = 0; i < a->m_IndiceTypes.size(); ++i ) + { + auto indice = a->m_IndiceTypes[ i ]; + auto exprIndice = b->m_IndiceTypes[ i ]; + + if ( !indice->DeepEquals( exprIndice ) ) + return false; + } + + return true; + } + + void DeepCopyFunctionType( const Type_t& from, Type_t* to ) + { + // Copy return type + to->m_ReturnType = DeepCopyType( *from.m_ReturnType, QS_NEW Type_t ); + + // Copy arguments + std::transform( from.m_ArgTypes.begin(), from.m_ArgTypes.end(), std::back_inserter( to->m_ArgTypes ), []( const NamedType_t& argument ) { + return std::make_pair( argument.first, DeepCopyType( *argument.second, QS_NEW Type_t ) ); + } ); + } + + void DeepCopyTableType( const Type_t& from, Type_t* to ) + { + // Copy properties + std::transform( from.m_PropTypes.begin(), from.m_PropTypes.end(), std::back_inserter( to->m_PropTypes ), []( const NamedType_t& prop ) { + return std::make_pair( prop.first, DeepCopyType( *prop.second, QS_NEW Type_t ) ); + } ); + } + + void DeepCopyArrayType( const Type_t& from, Type_t* to ) + { + // Copy array indices + std::transform( from.m_IndiceTypes.begin(), from.m_IndiceTypes.end(), std::back_inserter( to->m_IndiceTypes ), []( const Type_t* indice ) { + return DeepCopyType( *indice, QS_NEW Type_t ); + } ); + } + + bool Type_t::IsAssignable( const Type_t* exprType ) const + { + if ( IsUnknown() || exprType->IsUnknown() ) + return true; + + // Require types to overlap + if ( ( m_Bits & exprType->m_Bits ) == 0 ) + return false; + + if ( exprType->m_Bits & TYPE_FUNCTION ) + { + if ( !FunctionTypeEqualStrict( this, exprType ) ) + return false; + } + + if ( exprType->m_Bits & TYPE_TABLE ) + { + if ( !TableTypeEqualStrict( this, exprType ) ) + return false; + } + + if ( exprType->m_Bits & TYPE_ARRAY ) + { + if ( !ArrayTypeEqualStrict( this, exprType ) ) + return false; + } + + return true; + } + + bool Type_t::DeepEquals( const Type_t* other ) const + { + // Require types to be same + if ( m_Bits != other->m_Bits ) + return false; + + if ( other->m_Bits & TYPE_FUNCTION ) + { + if ( !FunctionTypeEqualStrict( this, other ) ) + return false; + } + + if ( other->m_Bits & TYPE_TABLE ) + { + if ( !TableTypeEqualStrict( this, other ) ) + return false; + } + + if ( other->m_Bits & TYPE_ARRAY ) + { + if ( !ArrayTypeEqualStrict( this, other ) ) + return false; + } + + return true; + } + + bool Type_t::Join( const Type_t* other ) + { + uint32_t unJoinable = TYPE_FUNCTION | TYPE_ARRAY | TYPE_TABLE; + + // Unjoinable types? This happens if any of unJoinable is in both + // this & other + if ( ( m_Bits & other->m_Bits ) & unJoinable ) + return false; + + // Copy extended types + if ( other->m_Bits & TYPE_FUNCTION ) + DeepCopyFunctionType( *other, this ); + + if ( other->m_Bits & TYPE_TABLE ) + DeepCopyTableType( *other, this ); + + if ( other->m_Bits & TYPE_ARRAY ) + DeepCopyArrayType( *other, this ); + + return true; + } + + void _DeepCopyType( const Type_t& source, Type_t* destination ) + { + // Copy type bits + destination->m_Bits = source.m_Bits; + + if ( source.m_Bits & TYPE_FUNCTION ) + DeepCopyFunctionType( source, destination ); + + if ( source.m_Bits & TYPE_TABLE ) + DeepCopyTableType( source, destination ); + + if ( source.m_Bits & TYPE_ARRAY ) + DeepCopyArrayType( source, destination ); + } + + Type_t* DeepCopyType( const Type_t& source, Type_t* newType ) + { + _DeepCopyType( source, newType ); + return newType; + } + + void FreeTypes( const Type_t* types ) + { + if ( !types ) + return; + + FreeTypes( types->m_ReturnType ); + + for ( auto arg : types->m_ArgTypes ) + FreeTypes( arg.second ); + + for ( auto prop : types->m_PropTypes ) + FreeTypes( prop.second ); + + for ( auto indice : types->m_IndiceTypes ) + FreeTypes( indice ); + + delete types; + } + + std::string TypeToString( const Type_t& type ) + { + if ( type.IsUnknown() ) + return "unknown"; + + std::string result = ""; + + std::map< CompileTypeBits, std::string > typeStrings ={ + { TYPE_NULL, "null" }, + { TYPE_NUMBER, "num" }, + { TYPE_BOOL, "bool" }, + { TYPE_TABLE, "Table" }, + { TYPE_ARRAY, "Array" }, + { TYPE_FUNCTION, "function" }, + { TYPE_NATIVE, "native" }, + { TYPE_STRING, "string" }, + { TYPE_NONE, "none" }, + }; + + for ( auto typeString : typeStrings ) + { + if ( type.m_Bits & typeString.first ) + { + if ( result.length() > 0 ) + result += " | " + typeString.second; + else + result = typeString.second; + } + } + + return result.length() > 0 ? result : "not_supported"; + } +} diff --git a/Library/Compiler/Types.h b/Library/Compiler/Types.h new file mode 100644 index 0000000..5f330ad --- /dev/null +++ b/Library/Compiler/Types.h @@ -0,0 +1,70 @@ +#pragma once + +namespace Compiler +{ + struct Type_t; + using NamedType_t = std::pair< std::string, Type_t* >; + + enum CompileTypeBits : uint32_t + { + // Primitives + TYPE_UNKNOWN = ( 0 << 0 ), + TYPE_NULL = ( 1 << 0 ), + TYPE_NUMBER = ( 1 << 1 ), + TYPE_BOOL = ( 1 << 2 ), + + // Objects + TYPE_TABLE = ( 1 << 3 ), + TYPE_CLOSURE = ( 1 << 4 ), + TYPE_FUNCTION = ( 1 << 5 ), + TYPE_INSTANCE = ( 1 << 6 ), + TYPE_NATIVE = ( 1 << 7 ), + TYPE_STRING = ( 1 << 8 ), + TYPE_UPVALUE = ( 1 << 9 ), + TYPE_ARRAY = ( 1 << 10 ), + + // No type (statements) + TYPE_NONE = ( 1 << 11 ), + + // Hint compiler to deduce type + TYPE_AUTO = ( 1 << 12 ), + }; + + struct Type_t + { + Type_t() : m_Bits( TYPE_NONE ) + { + m_ReturnType = NULL; + } + + Type_t( uint32_t bits ) : m_Bits( bits ) + { + m_ReturnType = NULL; + } + + Type_t( uint32_t bits, uint32_t returnBits ) : m_Bits( bits ) + { + m_ReturnType = QS_NEW Type_t( returnBits ); + } + + bool IsUnknown() const { return m_Bits == TYPE_UNKNOWN; } + bool IsAuto() const { return m_Bits == TYPE_AUTO; } + bool HasPrimitive( uint32_t primitiveType ) const { return !!( m_Bits & primitiveType ); } + bool IsPrimitive( uint32_t primitiveType ) const { return m_Bits == primitiveType; } + + bool IsAssignable( const Type_t* exprType ) const; + bool DeepEquals( const Type_t* other ) const; + bool Join( const Type_t* other ); + + uint32_t m_Bits; + Type_t* m_ReturnType; // Function returns + + std::vector< NamedType_t > m_ArgTypes; // Function arguments + std::vector< NamedType_t > m_PropTypes; // Table props + std::vector< Type_t* > m_IndiceTypes; // Array indices + }; + + //void DeepCopyType( const Type_t& source, Type_t* destination ); + Type_t* DeepCopyType( const Type_t& other, Type_t* allocated ); + void FreeTypes( const Type_t* types ); +} \ No newline at end of file diff --git a/Library/Library.vcxproj b/Library/Library.vcxproj index 495c091..756adac 100644 --- a/Library/Library.vcxproj +++ b/Library/Library.vcxproj @@ -160,6 +160,7 @@ + @@ -180,6 +181,7 @@ + diff --git a/Library/Library.vcxproj.filters b/Library/Library.vcxproj.filters index 721ba09..66cd3aa 100644 --- a/Library/Library.vcxproj.filters +++ b/Library/Library.vcxproj.filters @@ -66,6 +66,9 @@ STL + + Compiler + @@ -119,5 +122,8 @@ Common + + Compiler + \ No newline at end of file diff --git a/Library/STL/NativeModule.h b/Library/STL/NativeModule.h index 894fb1b..de544dd 100644 --- a/Library/STL/NativeModule.h +++ b/Library/STL/NativeModule.h @@ -1,5 +1,11 @@ #pragma once +#define NATIVE_ASSEMBLER_GLOBAL( name, _type, _returnType ) { \ +auto typeDef = QS_NEW Compiler::Type_t( _type, _returnType ); \ +assembler->AddGlobal( name, true, -1, -1, typeDef ); \ +Compiler::FreeTypes( typeDef ); \ +} + struct VM_t; namespace Compiler diff --git a/Library/STL/System.cpp b/Library/STL/System.cpp index 7c32a26..37dee0e 100644 --- a/Library/STL/System.cpp +++ b/Library/STL/System.cpp @@ -5,6 +5,7 @@ #include "../Common/Chunk.h" #include "../Compiler/Compiler.h" +#include "../Compiler/Types.h" #include "../Runtime/QVM.h" #include @@ -28,8 +29,9 @@ void SystemModule::Import( VM_t* vm ) const void SystemModule::Import( Compiler::Assembler* assembler, int lineNr, int colNr ) const { auto config = assembler->Config(); - assembler->AddGlobal( "exit", true, -1, -1, Compiler::TYPE_NATIVE, Compiler::TYPE_NONE ); - assembler->AddGlobal( "print", true, -1, -1, Compiler::TYPE_NATIVE, Compiler::TYPE_NONE ); + + NATIVE_ASSEMBLER_GLOBAL( "print", Compiler::TYPE_NATIVE, Compiler::TYPE_NONE ); + NATIVE_ASSEMBLER_GLOBAL( "exit", Compiler::TYPE_NATIVE, Compiler::TYPE_NONE ); if ( config.m_ImportCb ) { diff --git a/Library/STL/Time.cpp b/Library/STL/Time.cpp index 2a02e50..4246ec2 100644 --- a/Library/STL/Time.cpp +++ b/Library/STL/Time.cpp @@ -4,6 +4,7 @@ #include "../Common/Chunk.h" #include "../Compiler/Compiler.h" +#include "../Compiler/Types.h" #include "../Runtime/QVM.h" #include @@ -23,7 +24,7 @@ void TimeModule::Import( VM_t* vm ) const void TimeModule::Import( Compiler::Assembler* assembler, int lineNr, int colNr ) const { auto& config = assembler->Config(); - assembler->AddGlobal( "clock", true, -1, -1, Compiler::TYPE_NATIVE, Compiler::TYPE_NUMBER ); + NATIVE_ASSEMBLER_GLOBAL( "clock", Compiler::TYPE_NATIVE, Compiler::TYPE_NUMBER ); if ( config.m_ImportCb ) { diff --git a/Tests/TestCompiler.cpp b/Tests/TestCompiler.cpp index 8131fd7..ee63fd4 100644 --- a/Tests/TestCompiler.cpp +++ b/Tests/TestCompiler.cpp @@ -187,33 +187,32 @@ bool Tests::TestCompiler() UTEST_CASE_CLOSED(); }( ); - UTEST_CASE( "Expression type checks" ) - { - UTEST_ASSERT( QScript::Typer( "auto x = 4 - 4 + 2 * 2;" )[ 0 ].first == TYPE_NUMBER ); + //UTEST_CASE( "Expression type checks" ) + //{ + // UTEST_ASSERT( QScript::Typer( "auto x = 4 - 4 + 2 * 2;" )[ 0 ].first == TYPE_NUMBER ); + // UTEST_ASSERT( QScript::Typer( "auto x = (4 - 4) + 2 + \"2\";" )[ 0 ].first == TYPE_STRING ); - UTEST_ASSERT( QScript::Typer( "auto x = (4 - 4) + 2 + \"2\";" )[ 0 ].first == TYPE_STRING ); + // UTEST_THROW_EXCEPTION( QScript::Compile( "var x = 2 - \"str\";" ), + // const std::vector< CompilerException >& e, + // e.size() == 1 && e[ 0 ].id() == "cp_invalid_expression_type" ); - UTEST_THROW_EXCEPTION( QScript::Compile( "var x = 2 - \"str\";" ), - const std::vector< CompilerException >& e, - e.size() == 1 && e[ 0 ].id() == "cp_invalid_expression_type" ); + // UTEST_CASE_CLOSED(); + //}( ); - UTEST_CASE_CLOSED(); - }( ); + //UTEST_CASE( "Function return types" ) + //{ + // UTEST_ASSERT( QScript::Typer( "const auto x = (num a, string b) -> { return a + b; };" )[ 0 ].second == TYPE_UNKNOWN ); - UTEST_CASE( "Function return types" ) - { - UTEST_ASSERT( QScript::Typer( "const auto x = (num a, string b) -> { return a + b; };" )[ 0 ].second == TYPE_UNKNOWN ); + // UTEST_ASSERT( ( QScript::Typer( "const auto x = (num a, string b) -> auto { return a + b; };" )[ 0 ].second & TYPE_STRING ) == TYPE_STRING ); - UTEST_ASSERT( ( QScript::Typer( "const auto x = (num a, string b) -> auto { return a + b; };" )[ 0 ].second & TYPE_STRING ) == TYPE_STRING ); + // UTEST_ASSERT( ( QScript::Typer( "const auto x = (num a, num b) -> auto { return a + b; };" )[ 0 ].second & TYPE_NUMBER ) == TYPE_NUMBER ); - UTEST_ASSERT( ( QScript::Typer( "const auto x = (num a, num b) -> auto { return a + b; };" )[ 0 ].second & TYPE_NUMBER ) == TYPE_NUMBER ); + // UTEST_THROW_EXCEPTION( QScript::Compile( "const x = () -> num { return \"abcdefg\"; };" ), + // const std::vector< CompilerException >& e, + // e.size() == 1 && e[ 0 ].id() == "cp_invalid_expression_type" ); - UTEST_THROW_EXCEPTION( QScript::Compile( "const x = () -> num { return \"abcdefg\"; };" ), - const std::vector< CompilerException >& e, - e.size() == 1 && e[ 0 ].id() == "cp_invalid_expression_type" ); - - UTEST_CASE_CLOSED(); - }( ); + // UTEST_CASE_CLOSED(); + //}( ); UTEST_CASE( "Function args types" ) { diff --git a/Tests/Tests.cpp b/Tests/Tests.cpp index 2fab51b..a2bc1a8 100644 --- a/Tests/Tests.cpp +++ b/Tests/Tests.cpp @@ -25,9 +25,9 @@ int main( int argc, const char** argv ) bool allPassed = true; std::vector< bool > testResults; - testResults.push_back( Tests::TestLexer() ); + //testResults.push_back( Tests::TestLexer() ); testResults.push_back( Tests::TestCompiler() ); - testResults.push_back( Tests::TestInterpreter() ); + //testResults.push_back( Tests::TestInterpreter() ); for ( auto result : testResults ) if ( !result ) allPassed = false; diff --git a/Tests/Tests.vcxproj b/Tests/Tests.vcxproj index 890d1b7..dd6c83e 100644 --- a/Tests/Tests.vcxproj +++ b/Tests/Tests.vcxproj @@ -176,6 +176,7 @@ + diff --git a/Tests/Tests.vcxproj.filters b/Tests/Tests.vcxproj.filters index 916b8c1..ec35017 100644 --- a/Tests/Tests.vcxproj.filters +++ b/Tests/Tests.vcxproj.filters @@ -78,6 +78,9 @@ Code + + Code + From 5b78d83f6b3af8c92e5fe4644dec1733c3ea8359 Mon Sep 17 00:00:00 2001 From: fakelag <35497506+fakelag@users.noreply.github.com> Date: Wed, 14 Apr 2021 18:59:45 +0300 Subject: [PATCH 3/3] Patching types (still wip) --- CLI/CLI.cpp | 66 +++++++-------- CLI/CLI.vcxproj | 10 +-- Includes/QScript.h | 2 +- LangSrv/LangSrv.vcxproj | 10 +-- Library/Compiler/AST/AST.cpp | 76 +++++++++-------- Library/Compiler/AST/AST.h | 3 +- Library/Compiler/AST/Typing.cpp | 11 ++- Library/Compiler/Compiler.cpp | 139 ++++++++++++++++---------------- Library/Compiler/Compiler.h | 4 +- Library/Compiler/Types.cpp | 12 +-- Library/Compiler/Types.h | 9 ++- Library/Library.vcxproj | 10 +-- Library/STL/NativeModule.h | 2 +- Tests/Tests.cpp | 4 +- Tests/Tests.vcxproj | 10 +-- exceptions.txt | 2 +- 16 files changed, 201 insertions(+), 169 deletions(-) diff --git a/CLI/CLI.cpp b/CLI/CLI.cpp index ffc3484..cdd9d64 100644 --- a/CLI/CLI.cpp +++ b/CLI/CLI.cpp @@ -105,38 +105,40 @@ int main( int argc, char* argv[] ) } else if ( GetArg( "--typer", argc, argv, &next ) ) { - //for (;;) - //{ - // try - // { - // std::string source = input; - - // if ( source.length() == 0 ) - // { - // std::cout << "Typer >"; - // std::getline( std::cin, source ); - // } - - // auto exprTypes = QScript::Typer( source ); - - // for ( auto type : exprTypes ) - // { - // if ( type.second != 1024 /* TYPE_NONE */ ) - // { - // std::cout << Compiler::TypeToString( type.first ) - // << " -> " << Compiler::TypeToString( type.second ) << std::endl; - // } - // else - // { - // std::cout << Compiler::TypeToString( type.first ) << std::endl; - // } - // } - // } - // EXCEPTION_HANDLING; - - // if ( input.length() > 0 ) - // break; - //} + for (;;) + { + try + { + std::string source = input; + + if ( source.length() == 0 ) + { + std::cout << "Typer >"; + std::getline( std::cin, source ); + } + + // --file F:\Projects\qscript-language\Debug\program.qss + auto exprTypes = QScript::Typer( source ); + + for ( auto type : exprTypes ) + { + //if ( type.second != 1024 /* TYPE_NONE */ ) + //{ + // std::cout << Compiler::TypeToString( type.first ) + // << " -> " << Compiler::TypeToString( type.second ) << std::endl; + //} + //else + //{ + // std::cout << Compiler::TypeToString( type.first ) << std::endl; + //} + std::cout << Compiler::TypeToString( *type ) << std::endl; + } + } + EXCEPTION_HANDLING; + + if ( input.length() > 0 ) + break; + } } else if ( GetArg( "--json", argc, argv, &next ) ) { diff --git a/CLI/CLI.vcxproj b/CLI/CLI.vcxproj index a38ac19..cb9fcaf 100644 --- a/CLI/CLI.vcxproj +++ b/CLI/CLI.vcxproj @@ -22,32 +22,32 @@ 15.0 {8FAFE65A-8B53-48EB-94FF-841F5E4AD82C} CLI - 10.0.17763.0 + 10.0 Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte diff --git a/Includes/QScript.h b/Includes/QScript.h index 814feb7..03a9505 100644 --- a/Includes/QScript.h +++ b/Includes/QScript.h @@ -66,7 +66,7 @@ namespace QScript Chunk_t* AllocChunk(); FunctionObject* Compile( const std::string& source, const Config_t& config = Config_t( true ) ); - // std::vector< std::pair< uint32_t, uint32_t > > Typer( const std::string& source, const Config_t& config = Config_t( false ) ); + std::vector< Compiler::Type_t* > Typer( const std::string& source, const Config_t& config = Config_t( false ) ); std::vector< Compiler::BaseNode* > GenerateAST( const std::string& source ); void FreeChunk( Chunk_t* chunk ); diff --git a/LangSrv/LangSrv.vcxproj b/LangSrv/LangSrv.vcxproj index 7ce34d9..63f0f5d 100644 --- a/LangSrv/LangSrv.vcxproj +++ b/LangSrv/LangSrv.vcxproj @@ -22,32 +22,32 @@ 15.0 {330A0596-DB49-45E4-AD2C-43A15AA29D21} LangSrv - 10.0.17763.0 + 10.0 Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte diff --git a/Library/Compiler/AST/AST.cpp b/Library/Compiler/AST/AST.cpp index e7b3dab..2bf2b54 100644 --- a/Library/Compiler/AST/AST.cpp +++ b/Library/Compiler/AST/AST.cpp @@ -172,7 +172,7 @@ namespace Compiler case TYPE_UNKNOWN: case TYPE_BOOL: { - argsList.push_back( Argument_t( AS_STRING( varName )->GetString(), DeepCopyType( *varType, assembler.RegisterType( QS_NEW Type_t ) ), + argsList.push_back( Argument_t( AS_STRING( varName )->GetString(), DeepCopyType( *varType, assembler.RegisterType( QS_NEW Type_t, __FILE__, __LINE__ ) ), varNameNode->LineNr(), varNameNode->ColNr() ) ); break; } @@ -187,7 +187,7 @@ namespace Compiler case NODE_NAME: { argsList.push_back( Argument_t( AS_STRING( static_cast< ValueNode* >( arg )->GetValue() )->GetString(), - DeepCopyType( Type_t( TYPE_UNKNOWN ), assembler.RegisterType( QS_NEW Type_t ) ), arg->LineNr(), arg->ColNr() ) ); + DeepCopyType( Type_t( TYPE_UNKNOWN ), assembler.RegisterType( QS_NEW Type_t, __FILE__, __LINE__ ) ), arg->LineNr(), arg->ColNr() ) ); break; } default: @@ -209,7 +209,7 @@ namespace Compiler auto argNode = static_cast< ListNode* >( nodeList[ 0 ] ); - auto funcType = assembler.RegisterType( QS_NEW Type_t( TYPE_FUNCTION ) ); + auto funcType = assembler.RegisterType( QS_NEW Type_t( TYPE_FUNCTION ), __FILE__, __LINE__ ); funcType->m_ReturnType = QS_NEW Type_t; ResolveReturnType( funcNode, assembler, funcType->m_ReturnType ); @@ -218,18 +218,21 @@ namespace Compiler auto function = assembler.CreateFunction( name, isConst, funcType, isAnonymous, !isMember, QScript::AllocChunk() ); if ( isMember ) - assembler.AddLocal( "this", false, -1, -1, &Type_t( TYPE_TABLE ) ); + assembler.AddLocal( "this", false, -1, -1, &TA_TABLE ); assembler.PushScope(); // Create args in scope auto argsList = ParseArgsList( argNode, assembler ); std::for_each( argsList.begin(), argsList.end(), [ &assembler, &function, &funcType ]( const Argument_t& item ) { - funcType->m_ArgTypes.push_back( NamedType_t{ item.m_Name, item.m_Type } ); // Give type ownership to function type + // Give type ownership to function type + assembler.UnregisterType( item.m_Type ); + funcType->m_ArgTypes.push_back( NamedType_t{ item.m_Name, item.m_Type } ); + assembler.AddLocal( item.m_Name, true, item.m_LineNr, item.m_ColNr, item.m_Type ); } ); - function->SetNumArgs( argsList.size() ); + function->SetNumArgs( ( int ) argsList.size() ); // Compile function body for ( auto node : static_cast< ListNode* >( nodeList[ 1 ] )->GetList() ) @@ -261,7 +264,7 @@ namespace Compiler else { // Free temporary return type holder - FreeTypes( assembler.UnregisterType( funcType ) ); + FreeTypes( assembler.UnregisterType( funcType ), __FILE__, __LINE__ ); } @@ -270,12 +273,13 @@ namespace Compiler BaseNode::BaseNode( int lineNr, int colNr, const std::string token, NodeType type, NodeId id ) { - m_LineNr = lineNr; - m_ColNr = colNr; - m_Token = token; - m_NodeType = type; - m_NodeId = id; - m_ExprType = QS_NEW Type_t( TYPE_NONE ); + m_LineNr = lineNr; + m_ColNr = colNr; + m_Token = token; + m_NodeType = type; + m_NodeId = id; + m_ExprType = QS_NEW Type_t( TYPE_NONE ); + m_ExprReturnType = QS_NEW Type_t( TYPE_UNKNOWN ); } TermNode::TermNode( int lineNr, int colNr, const std::string token, NodeId id ) @@ -285,7 +289,10 @@ namespace Compiler void TermNode::Release() { - FreeTypes( m_ExprType ); + if ( m_ExprType->m_ReturnType != m_ExprReturnType ) + FreeTypes( m_ExprReturnType, __FILE__, __LINE__ ); + + FreeTypes( m_ExprType, __FILE__, __LINE__ ); m_ExprType = NULL; } @@ -306,7 +313,7 @@ namespace Compiler if ( type->m_ReturnType ) { - if ( !type->m_ReturnType->IsAssignable( &Type_t( TYPE_NULL ) ) ) + if ( !type->m_ReturnType->IsAssignable( &TA_NULL ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + TypeToString( *type->m_ReturnType ) + ", got: " + TypeToString( Type_t( TYPE_NULL ) ), @@ -333,7 +340,7 @@ namespace Compiler void ValueNode::Release() { - FreeTypes( m_ExprType ); + FreeTypes( m_ExprType, __FILE__, __LINE__ ); m_ExprType = NULL; } @@ -506,7 +513,7 @@ namespace Compiler delete m_Right; } - FreeTypes( m_ExprType ); + FreeTypes( m_ExprType, __FILE__, __LINE__ ); m_ExprType = NULL; } @@ -814,7 +821,7 @@ namespace Compiler // Perform type checking auto targetType = node->ExprType( assembler ); - if ( !targetType->IsAssignable( &Type_t( TYPE_NUMBER ) ) ) + if ( !targetType->IsAssignable( &TA_NUMBER ) ) { throw CompilerException( "cp_invalid_expression_type", "Can not assign expression of type " + TypeToString( Type_t( TYPE_NUMBER ) ) + " to variable of type " + TypeToString( *targetType ), @@ -877,14 +884,14 @@ namespace Compiler if ( opCode != numberOps.end() ) { // Type check: Number - if ( !leftType->IsAssignable( &Type_t( TYPE_NUMBER ) ) ) + if ( !leftType->IsAssignable( &TA_NUMBER ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( *leftType ), m_Left->LineNr(), m_Left->ColNr(), m_Left->Token() ); } - if ( !rightType->IsAssignable( &Type_t( TYPE_NUMBER ) ) ) + if ( !rightType->IsAssignable( &TA_NUMBER ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + TypeToString( Type_t( TYPE_NUMBER ) ) + ", got: " + TypeToString( *rightType ), @@ -950,7 +957,7 @@ namespace Compiler delete m_Node; } - FreeTypes( m_ExprType ); + FreeTypes( m_ExprType, __FILE__, __LINE__ ); m_ExprType = NULL; } @@ -1005,8 +1012,8 @@ namespace Compiler { // Check return type match auto type = assembler.CurrentContext()->m_Type; - auto retnType = type->m_ReturnType ? type->m_ReturnType : &Type_t( TYPE_UNKNOWN ); - auto exprType = m_Node ? m_Node->ExprType( assembler ) : &Type_t( TYPE_NULL ); + auto retnType = type->m_ReturnType ? type->m_ReturnType : &TA_UNKNOWN; + auto exprType = m_Node ? m_Node->ExprType( assembler ) : &TA_NULL; if ( !retnType->IsAssignable( exprType ) ) { @@ -1054,7 +1061,7 @@ namespace Compiler m_NodeList.clear(); - FreeTypes( m_ExprType ); + FreeTypes( m_ExprType, __FILE__, __LINE__ ); m_ExprType = NULL; } @@ -1101,7 +1108,7 @@ namespace Compiler if ( !isLocal ) { // Global variable - if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, &Type_t( TYPE_TABLE ) ) ) + if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, &TA_TABLE ) ) { throw CompilerException( "cp_identifier_already_exists", "Identifier \"" + varNameString + "\" already exists", m_LineNr, m_ColNr, m_Token ); @@ -1112,7 +1119,7 @@ namespace Compiler else { // Local variable - assembler.AddLocal( varNameString, true, lineNr, colNr, &Type_t( TYPE_TABLE ) ); + assembler.AddLocal( varNameString, true, lineNr, colNr, &TA_TABLE ); } } else @@ -1250,7 +1257,7 @@ namespace Compiler if ( !isLocal ) { - if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, &Type_t( TYPE_ARRAY ) ) ) + if ( !assembler.AddGlobal( varNameString, true, lineNr, colNr, &TA_ARRAY ) ) { throw CompilerException( "cp_identifier_already_exists", "Identifier \"" + varNameString + "\" already exists", m_LineNr, m_ColNr, m_Token ); @@ -1260,7 +1267,7 @@ namespace Compiler } else { - assembler.AddLocal( varNameString, true, lineNr, colNr, &Type_t( TYPE_ARRAY ) ); + assembler.AddLocal( varNameString, true, lineNr, colNr, &TA_ARRAY ); } } @@ -1524,7 +1531,7 @@ namespace Compiler if ( fn ) { // Free temporary function type - FreeTypes( assembler.UnregisterType( varType ) ); + FreeTypes( assembler.UnregisterType( varType ), __FILE__, __LINE__ ); } } else @@ -1535,20 +1542,21 @@ namespace Compiler // Empty variable EmitByte( QScript::OpCode::OP_LOAD_NULL, chunk ); - if ( !varType->IsAssignable( &Type_t( TYPE_NULL ) ) ) + if ( !varType->IsAssignable( &TA_NULL ) ) { throw CompilerException( "cp_invalid_expression_type", "Expected expression of type " + TypeToString( *varType ) + ", got: " + TypeToString( Type_t( TYPE_NULL ) ), lineNr, colNr, m_NodeList[ 0 ]->Token() ); } - auto unknownType = assembler.RegisterType( QS_NEW Type_t( TYPE_UNKNOWN, TYPE_UNKNOWN ) ); + auto unknownType = assembler.RegisterType( QS_NEW Type_t( TYPE_UNKNOWN, TYPE_UNKNOWN ), __FILE__, __LINE__ ); if ( !isLocal ) { // Global variable if ( !assembler.AddGlobal( varString, isConst, lineNr, colNr, unknownType ) ) { + FreeTypes( assembler.UnregisterType( unknownType ), __FILE__, __LINE__ ); throw CompilerException( "cp_identifier_already_exists", "Identifier \"" + varString + "\" already exists", m_NodeList[ 0 ]->LineNr(), m_NodeList[ 0 ]->ColNr(), m_NodeList[ 0 ]->Token() ); } @@ -1562,7 +1570,7 @@ namespace Compiler assembler.AddLocal( varString, isConst, lineNr, colNr, unknownType ); } - FreeTypes( assembler.UnregisterType( unknownType ) ); + FreeTypes( assembler.UnregisterType( unknownType ), __FILE__, __LINE__ ); } break; } @@ -1612,10 +1620,10 @@ namespace Compiler void TypeNode::Release() { - FreeTypes( m_ExprType ); + FreeTypes( m_ExprType, __FILE__, __LINE__ ); m_ExprType = NULL; - FreeTypes( m_Type ); + FreeTypes( m_Type, __FILE__, __LINE__ ); m_Type = NULL; } diff --git a/Library/Compiler/AST/AST.h b/Library/Compiler/AST/AST.h index aa3f20c..32c8e61 100644 --- a/Library/Compiler/AST/AST.h +++ b/Library/Compiler/AST/AST.h @@ -121,8 +121,9 @@ namespace Compiler int m_ColNr; std::string m_Token; - // Node expression type -- Updated and returnted by ExprType() + // Node expression type -- Updated and returned by ExprType() Type_t* m_ExprType; + Type_t* m_ExprReturnType; }; class TermNode : public BaseNode diff --git a/Library/Compiler/AST/Typing.cpp b/Library/Compiler/AST/Typing.cpp index d63fbb5..2127a1c 100644 --- a/Library/Compiler/AST/Typing.cpp +++ b/Library/Compiler/AST/Typing.cpp @@ -34,7 +34,7 @@ namespace Compiler for ( auto arg : argsList ) { assembler.AddArgument( arg.m_Name, true, arg.m_LineNr, arg.m_ColNr, arg.m_Type ); - FreeTypes( arg.m_Type ); + FreeTypes( assembler.UnregisterType( arg.m_Type ), __FILE__, __LINE__ ); } std::function< void( BaseNode* ) > visitNode; @@ -317,7 +317,14 @@ namespace Compiler { case NODE_TABLE: EXPR_TYPE_STATIC( TYPE_TABLE ); break; case NODE_ARRAY: EXPR_TYPE_STATIC( TYPE_ARRAY ); break; - case NODE_FUNC: EXPR_TYPE_STATIC( TYPE_FUNCTION ); break; + case NODE_FUNC: { + //EXPR_TYPE_STATIC( TYPE_FUNCTION ); + //break; + m_ExprType->m_Bits = TYPE_FUNCTION; + m_ExprReturnType->m_Bits = TYPE_UNKNOWN; + m_ExprType->m_ReturnType = m_ExprReturnType; + break; + } case NODE_INLINE_IF: { EXPR_TYPE_FROM_CHILD( m_NodeList[ 1 ] ); diff --git a/Library/Compiler/Compiler.cpp b/Library/Compiler/Compiler.cpp index 72fb6fd..998e0c8 100644 --- a/Library/Compiler/Compiler.cpp +++ b/Library/Compiler/Compiler.cpp @@ -116,7 +116,7 @@ namespace QScript } } - /*std::vector< std::pair< uint32_t, uint32_t > > Typer( const std::string& source, const Config_t& config ) + std::vector< Compiler::Type_t* > Typer( const std::string& source, const Config_t& config ) { BEGIN_COMPILER; @@ -131,7 +131,7 @@ namespace QScript systemModule->Import( &assembler ); std::vector< Compiler::BaseNode* > astNodes; - std::vector< std::pair< uint32_t, uint32_t > > exprTypes; + std::vector< Compiler::Type_t* > exprTypes; try { @@ -145,68 +145,65 @@ namespace QScript delete astNodes.back(); astNodes.erase( astNodes.end() - 1 ); - // Compile bytecode for ( auto node : astNodes ) { node->Compile( assembler ); - uint32_t exprType = node->ExprType( assembler ); - uint32_t retnType = Compiler::TYPE_NONE; + auto exprType = node->ExprType( assembler ); + exprTypes.push_back( Compiler::DeepCopyType( *exprType, QS_NEW Compiler::Type_t ) ); // Attempt to resolve return type - if ( exprType == Compiler::TYPE_FUNCTION || exprType == Compiler::TYPE_NATIVE ) - { - switch ( node->Id() ) - { - case Compiler::NODE_NAME: - { - auto nameValue = static_cast< Compiler::ValueNode* >( node )->GetValue(); - auto name = AS_STRING( nameValue )->GetString(); - - Compiler::Variable_t varInfo; - - if ( assembler.FindGlobal( name, &varInfo ) ) - retnType = varInfo.m_Type->m_ReturnType ? varInfo.m_Type->m_ReturnType->m_Bits : Compiler::TYPE_NONE; - - break; - } - case Compiler::NODE_FUNC: - { - auto funcNode = static_cast< Compiler::ListNode* >( node ); - retnType = Compiler::ResolveReturnType( funcNode, assembler ); - break; - } - case Compiler::NODE_CONSTVAR: - case Compiler::NODE_VAR: - { - auto varNode = static_cast< Compiler::ListNode* >( node ); - auto valueNode = varNode->GetList()[ 1 ]; - - if ( valueNode && valueNode->Id() == Compiler::NODE_FUNC ) - { - auto funcNode = static_cast< Compiler::ListNode* >( valueNode ); - retnType = Compiler::ResolveReturnType( funcNode, assembler ); - } - break; - } - case Compiler::NODE_ASSIGN: - { - auto assignNode = static_cast< Compiler::ComplexNode* >( node ); - auto valueNode = assignNode->GetRight(); - - if ( valueNode && valueNode->Id() == Compiler::NODE_FUNC ) - { - auto funcNode = static_cast< const Compiler::ListNode* >( valueNode ); - retnType = Compiler::ResolveReturnType( funcNode, assembler ); - } - break; - } - default: - break; - } - } - - exprTypes.push_back( std::make_pair( exprType, retnType ) ); + //if ( exprType->IsPrimitive( Compiler::TYPE_FUNCTION ) || exprType->IsPrimitive( Compiler::TYPE_NATIVE ) ) + //{ + // switch ( node->Id() ) + // { + // case Compiler::NODE_NAME: + // { + // auto nameValue = static_cast< Compiler::ValueNode* >( node )->GetValue(); + // auto name = AS_STRING( nameValue )->GetString(); + + // Compiler::Variable_t varInfo; + + // if ( assembler.FindGlobal( name, &varInfo ) ) + // retnType = varInfo.m_Type->m_ReturnType ? *varInfo.m_Type->m_ReturnType : Compiler::Type_t( Compiler::TYPE_NONE ); + + // break; + // } + // case Compiler::NODE_FUNC: + // { + // auto funcNode = static_cast< Compiler::ListNode* >( node ); + // Compiler::ResolveReturnType( funcNode, assembler, retnType ); + // break; + // } + // case Compiler::NODE_CONSTVAR: + // case Compiler::NODE_VAR: + // { + // auto varNode = static_cast< Compiler::ListNode* >( node ); + // auto valueNode = varNode->GetList()[ 1 ]; + + // if ( valueNode && valueNode->Id() == Compiler::NODE_FUNC ) + // { + // auto funcNode = static_cast< Compiler::ListNode* >( valueNode ); + // retnType = Compiler::ResolveReturnType( funcNode, assembler ); + // } + // break; + // } + // case Compiler::NODE_ASSIGN: + // { + // auto assignNode = static_cast< Compiler::ComplexNode* >( node ); + // auto valueNode = assignNode->GetRight(); + + // if ( valueNode && valueNode->Id() == Compiler::NODE_FUNC ) + // { + // auto funcNode = static_cast< const Compiler::ListNode* >( valueNode ); + // retnType = Type::ResolveReturnType( funcNode, assembler ); + // } + // break; + // } + // default: + // break; + // } + //} } for ( auto node : astNodes ) @@ -268,7 +265,7 @@ namespace QScript // Rethrow throw; } - }*/ + } std::vector< Compiler::BaseNode* > GenerateAST( const std::string& source ) { @@ -536,9 +533,9 @@ namespace Compiler { // Fill out globals for REPL for ( auto identifier : config.m_Globals ) - AddGlobal( identifier, false, -1, -1, &Type_t( TYPE_UNKNOWN ), NULL ); + AddGlobal( identifier, false, -1, -1, &TA_UNKNOWN, NULL ); - CreateFunction( "
", true, &Type_t( TYPE_UNKNOWN ), true, true, chunk ); + CreateFunction( "
", true, &TA_UNKNOWN, true, true, chunk ); } void Assembler::Release() @@ -547,7 +544,7 @@ namespace Compiler // materials need to be freed for ( auto type : m_Types ) - FreeTypes( type ); + FreeTypes( type, __FILE__, __LINE__ ); for ( auto context : m_Functions ) { @@ -565,7 +562,7 @@ namespace Compiler delete CurrentStack(); for ( auto type : m_Types ) - FreeTypes( type ); + FreeTypes( type, __FILE__, __LINE__ ); m_Compiled.push_back( m_Functions[ 0 ].m_Func ); m_Functions.pop_back(); @@ -601,7 +598,7 @@ namespace Compiler QScript::FunctionObject* Assembler::CreateFunction( const std::string& name, bool isConst, const Type_t* type, bool isAnonymous, bool addLocal, QScript::Chunk_t* chunk ) { auto function = QS_NEW QScript::FunctionObject( name, chunk ); - auto context = FunctionContext_t{ function, QS_NEW Assembler::Stack_t(), DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ) }; + auto context = FunctionContext_t{ function, QS_NEW Assembler::Stack_t(), DeepCopyType( *type, RegisterType( QS_NEW Type_t, __FILE__, __LINE__ ) ) }; m_Functions.push_back( context ); @@ -640,7 +637,7 @@ namespace Compiler void Assembler::AddArgument( const std::string& name, bool isConstant, int lineNr, int colNr, const Type_t* type ) { - auto variable = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ) ); + auto variable = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t, __FILE__, __LINE__ ) ) ); if ( m_Config.m_IdentifierCb ) m_Config.m_IdentifierCb( lineNr, colNr, variable, "Argument" ); @@ -652,7 +649,7 @@ namespace Compiler { auto stack = CurrentStack(); - auto variable = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ), fn ); + auto variable = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t, __FILE__, __LINE__ ) ), fn ); if ( m_Config.m_IdentifierCb ) m_Config.m_IdentifierCb( lineNr, colNr, variable, "Local" ); @@ -734,7 +731,7 @@ namespace Compiler if ( m_Globals.find( name ) != m_Globals.end() ) return false; - Variable_t global = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t ) ), fn ); + Variable_t global = Variable_t( name, isConstant, DeepCopyType( *type, RegisterType( QS_NEW Type_t, __FILE__, __LINE__ ) ), fn ); m_Globals.insert( std::make_pair( name, global ) ); if ( m_Config.m_IdentifierCb ) @@ -827,8 +824,14 @@ namespace Compiler --stack->m_CurrentDepth; } - Type_t* Assembler::RegisterType( Type_t* type ) + Type_t* Assembler::RegisterType( Type_t* type, const char* file, int line ) { + if ( std::find( m_Types.begin(), m_Types.end(), type ) != m_Types.end() ) { + throw std::exception( "Type already exists in registered types. There is a programming error." ); + } + + // printf( "type %X registerted from %s line %i\n", type, file, line ); + m_Types.push_back( type ); return type; } diff --git a/Library/Compiler/Compiler.h b/Library/Compiler/Compiler.h index 9006a15..7502344 100644 --- a/Library/Compiler/Compiler.h +++ b/Library/Compiler/Compiler.h @@ -118,7 +118,7 @@ namespace Compiler bool IsTopLevel(); void PopScope(); void PushScope(); - Type_t* RegisterType( Type_t* type ); + Type_t* RegisterType( Type_t* type, const char* file, int line ); void Release(); bool RequestUpvalue( const std::string name, uint32_t* out, int lineNr, int colNr, Variable_t* varInfo ); int StackDepth(); @@ -133,4 +133,6 @@ namespace Compiler std::map< std::string, Variable_t > m_Globals; std::vector< Type_t* > m_Types; }; + + //void ResolveReturnType( ListNode* funcNode, Assembler& assembler, Type_t* out ); }; diff --git a/Library/Compiler/Types.cpp b/Library/Compiler/Types.cpp index 642a9c4..a67903b 100644 --- a/Library/Compiler/Types.cpp +++ b/Library/Compiler/Types.cpp @@ -193,21 +193,23 @@ namespace Compiler return newType; } - void FreeTypes( const Type_t* types ) + void FreeTypes( const Type_t* types, const char* file, int line ) { + // printf( "FreeTypes %X from %s line %i\n", types, file, line ); + if ( !types ) return; - FreeTypes( types->m_ReturnType ); + FreeTypes( types->m_ReturnType, __FILE__, __LINE__ ); for ( auto arg : types->m_ArgTypes ) - FreeTypes( arg.second ); + FreeTypes( arg.second, __FILE__, __LINE__ ); for ( auto prop : types->m_PropTypes ) - FreeTypes( prop.second ); + FreeTypes( prop.second, __FILE__, __LINE__ ); for ( auto indice : types->m_IndiceTypes ) - FreeTypes( indice ); + FreeTypes( indice, __FILE__, __LINE__ ); delete types; } diff --git a/Library/Compiler/Types.h b/Library/Compiler/Types.h index 5f330ad..265c6d4 100644 --- a/Library/Compiler/Types.h +++ b/Library/Compiler/Types.h @@ -66,5 +66,12 @@ namespace Compiler //void DeepCopyType( const Type_t& source, Type_t* destination ); Type_t* DeepCopyType( const Type_t& other, Type_t* allocated ); - void FreeTypes( const Type_t* types ); + void FreeTypes( const Type_t* types, const char* file, int line ); + + // Type aliases + static const Type_t TA_NULL = Type_t( TYPE_NULL ); + static const Type_t TA_UNKNOWN = Type_t( TYPE_UNKNOWN ); + static const Type_t TA_TABLE = Type_t( TYPE_TABLE ); + static const Type_t TA_ARRAY = Type_t( TYPE_ARRAY ); + static const Type_t TA_NUMBER = Type_t( TYPE_NUMBER ); } \ No newline at end of file diff --git a/Library/Library.vcxproj b/Library/Library.vcxproj index 756adac..2600529 100644 --- a/Library/Library.vcxproj +++ b/Library/Library.vcxproj @@ -22,32 +22,32 @@ 15.0 {4E76C9F6-0B28-40CE-A125-FA20D399BABF} Library - 10.0.17763.0 + 10.0 StaticLibrary true - v141 + v142 MultiByte StaticLibrary false - v141 + v142 true MultiByte Application true - v141 + v142 MultiByte StaticLibrary false - v141 + v142 true MultiByte diff --git a/Library/STL/NativeModule.h b/Library/STL/NativeModule.h index de544dd..a6d45bf 100644 --- a/Library/STL/NativeModule.h +++ b/Library/STL/NativeModule.h @@ -3,7 +3,7 @@ #define NATIVE_ASSEMBLER_GLOBAL( name, _type, _returnType ) { \ auto typeDef = QS_NEW Compiler::Type_t( _type, _returnType ); \ assembler->AddGlobal( name, true, -1, -1, typeDef ); \ -Compiler::FreeTypes( typeDef ); \ +Compiler::FreeTypes( typeDef, __FILE__, __LINE__ ); \ } struct VM_t; diff --git a/Tests/Tests.cpp b/Tests/Tests.cpp index a2bc1a8..2fab51b 100644 --- a/Tests/Tests.cpp +++ b/Tests/Tests.cpp @@ -25,9 +25,9 @@ int main( int argc, const char** argv ) bool allPassed = true; std::vector< bool > testResults; - //testResults.push_back( Tests::TestLexer() ); + testResults.push_back( Tests::TestLexer() ); testResults.push_back( Tests::TestCompiler() ); - //testResults.push_back( Tests::TestInterpreter() ); + testResults.push_back( Tests::TestInterpreter() ); for ( auto result : testResults ) if ( !result ) allPassed = false; diff --git a/Tests/Tests.vcxproj b/Tests/Tests.vcxproj index dd6c83e..ae43718 100644 --- a/Tests/Tests.vcxproj +++ b/Tests/Tests.vcxproj @@ -22,32 +22,32 @@ 15.0 {3EFF8713-E68B-4B19-BC4B-4EC30165A7C1} Tests - 10.0.17763.0 + 10.0 Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte diff --git a/exceptions.txt b/exceptions.txt index 4a35bc1..f874a40 100644 --- a/exceptions.txt +++ b/exceptions.txt @@ -45,4 +45,4 @@ Runtime rt_unknown_property Unknown property "%propName%" of "%instance%" Runtime rt_exit exit() called Generic Exceptions -error_not_implemented reason: A feature is not yet implemented \ No newline at end of file +error_not_implemented reason: A feature is not yet implemented