Skip to content

Commit

Permalink
Dereference pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
Shachar committed Nov 21, 2020
1 parent 1c0122b commit 09a68d2
Show file tree
Hide file tree
Showing 21 changed files with 258 additions and 23 deletions.
10 changes: 10 additions & 0 deletions include/practical/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ class LValueRequired : public compile_error {
LValueRequired(StaticType::CPtr wrongType, const SourceLocation &location);
};

class PointerExpected : public compile_error {
public:
PointerExpected(StaticType::CPtr wrongType, const SourceLocation &location);
};

class KnownRuntimeViolation : public compile_error {
public:
KnownRuntimeViolation(const char *message, const SourceLocation &location);
};

} // PracticalSemanticAnalyzer

#endif // PRACTICAL_ERRORS_H
2 changes: 1 addition & 1 deletion lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ libpractical_sa_la_SOURCES = practical-sa.cpp practical-errors.cpp scope_tracing
ast/expression.cpp ast/expression/base.cpp ast/expression/literal.cpp ast/expression/identifier.cpp \
ast/expression/function_call.cpp ast/expression/binary_op.cpp ast/expression/overload_resolver.cpp \
ast/expression/compound_expression.cpp ast/expression/conditional_expression.cpp ast/expression/cast_op.cpp \
ast/expression/unary_op.cpp ast/expression/address_of.cpp \
ast/expression/unary_op.cpp ast/expression/address_of.cpp ast/expression/dereference.cpp \
ast/operators/helper.cpp ast/operators/algebraic_int.cpp ast/operators/boolean.cpp

practical_sa_ut_SOURCES = ut_runner.cpp slice_ut.cpp tokenizer_ut.cpp exact_int_ut.cpp \
Expand Down
3 changes: 2 additions & 1 deletion lib/ast/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "ast/decay.h"
#include "ast/signed_int_value_range.h"
#include "ast/unsigned_int_value_range.h"
#include "ast/void_value_range.h"

namespace AST {

Expand Down Expand Up @@ -48,7 +49,7 @@ void AST::registerBuiltinTypes( BuiltinContextGen *ctxGen ) {
// Types
auto voidType = builtinCtx.registerScalarType(
ScalarTypeImpl( "Void", "v", 0, 1, ScalarTypeImpl::Type::Void, ctxGen->registerVoidType(), 0 ),
nullptr );
new VoidValueRange() );
auto boolType = builtinCtx.registerScalarType(
ScalarTypeImpl( "Bool", "b", 1, 1, ScalarTypeImpl::Type::Bool, ctxGen->registerBoolType(), 0 ),
BoolValueRange::allocate() );
Expand Down
34 changes: 21 additions & 13 deletions lib/ast/expression/address_of.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,27 @@ void AddressOf::buildASTImpl(
Weight &weight, Weight weightLimit
)
{
StaticType::Types expectedType = expectedResult.getType()->getType();
auto expectedPointer = std::get_if<const StaticType::Pointer *>( &expectedType );

if( expectedPointer ) {
operand.buildAST(
lookupContext,
ExpectedResult(
(*expectedPointer)->getPointedType()->addFlags( StaticType::Flags::Reference ),
expectedResult.isMandatory() ),
weight,
weightLimit
);
} else {
bool handled = false;

if( expectedResult) {
StaticType::Types expectedType = expectedResult.getType()->getType();
auto expectedPointer = std::get_if<const StaticType::Pointer *>( &expectedType );

if( expectedPointer ) {
operand.buildAST(
lookupContext,
ExpectedResult(
(*expectedPointer)->getPointedType()->addFlags( StaticType::Flags::Reference ),
expectedResult.isMandatory() ),
weight,
weightLimit
);

handled = true;
}
}

if( !handled ) {
operand.buildAST( lookupContext, ExpectedResult(), weight, weightLimit );
}

Expand Down
2 changes: 0 additions & 2 deletions lib/ast/expression/base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@ void Base::buildAST( LookupContext &lookupContext, ExpectedResult expectedResult
if( weight>weightLimit )
throw ExpressionTooExpensive();

/*
ASSERT( metadata.type )<<"Build AST did not set a return type "<<getLocation();
ASSERT( metadata.valueRange )<<"Build AST did not set a value range "<<getLocation();
*/
if( !expectedResult || *expectedResult.getType()==*metadata.type )
return;

Expand Down
59 changes: 59 additions & 0 deletions lib/ast/expression/dereference.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* This file is part of the Practical programming langauge. https://github.com/Practical/practical-sa
*
* To the extent header files enjoy copyright protection, this file is file is copyright (C) 2020 by its authors
* You can see the file's authors in the AUTHORS file in the project's home repository.
*
* This is available under the Boost license. The license's text is available under the LICENSE file in the project's
* home directory.
*/
#include "ast/expression/dereference.h"

#include "ast/pointers.h"
#include "asserts.h"

#include <practical/errors.h>

namespace AST::ExpressionImpl {

Dereference::Dereference( const NonTerminals::Expression &parserOperand ) :
operand( parserOperand )
{}

void Dereference::buildASTImpl(
LookupContext &lookupContext, ExpectedResult expectedResult, ExpressionMetadata &metadata,
Weight &weight, Weight weightLimit
)
{
ExpectedResult expectedOperandResult;

if( expectedResult ) {
StaticTypeImpl::CPtr operandExpectedType =
StaticTypeImpl::allocate( PointerTypeImpl( expectedResult.getType() ) );

expectedOperandResult = ExpectedResult( std::move(operandExpectedType), expectedResult.isMandatory() );
}

operand.buildAST( lookupContext, expectedOperandResult, weight, weightLimit );

StaticType::Types resultTypeType = operand.getType()->getType();
auto resultPointerParent = std::get_if<const StaticType::Pointer *>( &resultTypeType );
if( !resultPointerParent )
throw PointerExpected(operand.getType(), operand.getLocation());

const PointerTypeImpl *resultPointer = downCast(*resultPointerParent);
ASSERT( resultPointer );

metadata.type = downCast( resultPointer->getPointedType()->setFlags( StaticType::Flags::Reference ) );

auto operandRange = operand.getValueRange()->downCast< PointerValueRange >();
if( operandRange->initialized.trueAllowed == false ) {
throw KnownRuntimeViolation( "Dereferencing a pointer known to be null", operand.getLocation() );
}
metadata.valueRange = operandRange->pointedValueRange;
}

ExpressionId Dereference::codeGen( PracticalSemanticAnalyzer::FunctionGen *functionGen ) const {
return operand.codeGen( functionGen );
}

} // namespace AST::ExpressionImpl
31 changes: 31 additions & 0 deletions lib/ast/expression/dereference.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* This file is part of the Practical programming langauge. https://github.com/Practical/practical-sa
*
* To the extent header files enjoy copyright protection, this file is file is copyright (C) 2020 by its authors
* You can see the file's authors in the AUTHORS file in the project's home repository.
*
* This is available under the Boost license. The license's text is available under the LICENSE file in the project's
* home directory.
*/
#ifndef AST_EXPRESSION_DEREFERENCE_H
#define AST_EXPRESSION_DEREFERENCE_H

#include "ast/expression.h"

namespace AST::ExpressionImpl {

class Dereference {
Expression operand;

public:
explicit Dereference( const NonTerminals::Expression &parserOperand );

void buildASTImpl(
LookupContext &lookupContext, ExpectedResult expectedResult, ExpressionMetadata &metadata,
Weight &weight, Weight weightLimit
);
ExpressionId codeGen( PracticalSemanticAnalyzer::FunctionGen *functionGen ) const;
};

} // namespace AST::ExpressionImpl

#endif // AST_EXPRESSION_DEREFERENCE_H
2 changes: 2 additions & 0 deletions lib/ast/expression/function_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ void FunctionCall::buildASTImpl(
lookupContext, expectedResult, function.overloads,
weight, weightLimit,
_this->metadata, Slice(arguments, numArguments), _this->parserFunctionCall.op );
_this->metadata.type = downCast( _this->resolver.getType().getReturnType() );
_this->metadata.valueRange = _this->metadata.type->defaultRange();
}
};

Expand Down
4 changes: 4 additions & 0 deletions lib/ast/expression/identifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* home directory.
*/
#include "ast/expression/identifier.h"
#include "ast/pointers.h"

#include <practical/errors.h>

Expand Down Expand Up @@ -48,6 +49,9 @@ void Identifier::buildASTImpl(

void operator()( const LookupContext::Function &func ) {
ASSERT( !expectedResult )<<"TODO implement choosing overload based on expected result";

_this->metadata.type = LookupContext::genericFunctionType();
_this->metadata.valueRange = LookupContext::genericFunctionRange();
}
};

Expand Down
10 changes: 10 additions & 0 deletions lib/ast/expression/overload_resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ void OverloadResolver::resolveOverloads(
}
}

const FunctionTypeImpl &OverloadResolver::getType() const {
ASSERT(definition)<<"Tried to getType from unresolved overloads";

auto functionTypeType = definition->type->getType();
auto functionType = std::get_if<const StaticType::Function *>( &functionTypeType );
ASSERT( functionType )<<"Function's type is not of type Function";

return *downCast(*functionType);
}

ExpressionId OverloadResolver::codeGen( PracticalSemanticAnalyzer::FunctionGen *functionGen ) const {
return definition->codeGen( arguments, definition, functionGen );
}
Expand Down
2 changes: 2 additions & 0 deletions lib/ast/expression/overload_resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class OverloadResolver {
const Tokenizer::Token *sourceLocation
);

const FunctionTypeImpl &getType() const;

ExpressionId codeGen( PracticalSemanticAnalyzer::FunctionGen *functionGen ) const;

private:
Expand Down
9 changes: 9 additions & 0 deletions lib/ast/expression/unary_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ void UnaryOp::buildASTImpl(
body.emplace<AddressOf>( *parserOp.operand ).
buildASTImpl(lookupContext, expectedResult, metadata, weight, weightLimit);
break;
case Tokenizer::Tokens::OP_PTR:
defaultHandling = false;
body.emplace<Dereference>( *parserOp.operand ).
buildASTImpl(lookupContext, expectedResult, metadata, weight, weightLimit);
break;
default:
break;
}
Expand Down Expand Up @@ -108,6 +113,10 @@ ExpressionId UnaryOp::codeGenImpl( PracticalSemanticAnalyzer::FunctionGen *funct
ExpressionId operator()( const AddressOf &addressOf ) {
return addressOf.codeGen( functionGen );
}

ExpressionId operator()( const Dereference &dereference ) {
return dereference.codeGen( functionGen );
}
};

return std::visit( Visitor{ .functionGen = functionGen }, body );
Expand Down
3 changes: 2 additions & 1 deletion lib/ast/expression/unary_op.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define AST_EXPRESSION_UNARY_OP_H

#include "ast/expression/address_of.h"
#include "ast/expression/dereference.h"
#include "ast/expression/overload_resolver.h"
#include "ast/expression.h"
#include "parser.h"
Expand All @@ -18,7 +19,7 @@ namespace AST::ExpressionImpl {

class UnaryOp final : public Base {
const NonTerminals::Expression::UnaryOperator &parserOp;
std::variant<std::monostate, OverloadResolver, AddressOf> body;
std::variant<std::monostate, OverloadResolver, AddressOf, Dereference> body;

public:
static void init(LookupContext &builtinCtx);
Expand Down
14 changes: 14 additions & 0 deletions lib/ast/lookup_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "ast/expression.h"
#include "ast/mangle.h"
#include "ast/pointers.h"

#include <asserts.h>

Expand All @@ -24,6 +25,11 @@ StaticType::CPtr LookupContext::Function::Definition::returnType() const {
return functionType->getReturnType();
}

StaticTypeImpl::CPtr LookupContext::_genericFunctionType =
StaticTypeImpl::allocate( FunctionTypeImpl( nullptr, {} ) );
ValueRangeBase::CPtr LookupContext::_genericFunctionRange =
new PointerValueRange( nullptr, BoolValueRange(false, false) );

StaticTypeImpl::CPtr LookupContext::lookupType( String name ) const {
auto iter = types.find( sliceToString(name) );

Expand Down Expand Up @@ -154,6 +160,14 @@ const LookupContext::Identifier *LookupContext::lookupIdentifier( String name )
return &iter->second;
}

StaticTypeImpl::CPtr LookupContext::genericFunctionType() {
return _genericFunctionType;
}

ValueRangeBase::CPtr LookupContext::genericFunctionRange() {
return _genericFunctionRange;
}

void LookupContext::addLocalVar( const Tokenizer::Token *token, StaticTypeImpl::CPtr type, ExpressionId lvalue ) {
auto iter = symbols.emplace( token->text, Variable(token, type, lvalue) );

Expand Down
7 changes: 7 additions & 0 deletions lib/ast/lookup_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ class LookupContext : private NoCopy {
PracticalSemanticAnalyzer::StaticType::CPtr destType);

// Members
static StaticTypeImpl::CPtr _genericFunctionType;
static ValueRangeBase::CPtr _genericFunctionRange;

std::unordered_map< std::string, StaticTypeImpl::CPtr > types;
const LookupContext *parent = nullptr;

Expand Down Expand Up @@ -153,6 +156,10 @@ class LookupContext : private NoCopy {

const Identifier *lookupIdentifier( String name ) const;

// Generic type and range to use for unspecified function
static StaticTypeImpl::CPtr genericFunctionType();
static ValueRangeBase::CPtr genericFunctionRange();

void addCast(
StaticTypeImpl::CPtr sourceType,
StaticTypeImpl::CPtr destType,
Expand Down
13 changes: 10 additions & 3 deletions lib/ast/pointers.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ class PointerValueRange final : public ValueRangeBase {
initialized( false, true )
{}

explicit PointerValueRange( ValueRangeBase::CPtr pointedRange, const BoolValueRange *initialized ) :
explicit PointerValueRange( ValueRangeBase::CPtr pointedRange, const BoolValueRange &initialized ) :
pointedValueRange( std::move(pointedRange) ),
initialized( initialized->falseAllowed, initialized->trueAllowed )
initialized( initialized.falseAllowed, initialized.trueAllowed )
{}

bool isLiteral() const override {
return initialized.isLiteral() && pointedValueRange && pointedValueRange->isLiteral();
if( ! initialized.isLiteral() )
return false;

if( initialized.falseAllowed )
return true;

ASSERT( pointedValueRange );
return pointedValueRange->isLiteral();
}
};

Expand Down
Loading

0 comments on commit 09a68d2

Please sign in to comment.