这是indexloc提供的服务,不要输入任何密码
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7c0984e
added new tests (for already existing functions)
Jun 2, 2022
985b4dd
whoops
Jun 2, 2022
b147c9e
Merge branch 'tuplex:master' into master
aletheia094 Jun 14, 2022
ed3a1b3
ignore commits to master branch
aletheia094 Jun 30, 2022
8128020
Revert "added new tests (for already existing functions)"
aletheia094 Jun 30, 2022
5ee3b28
Merge branch 'tuplex:master' into master
aletheia094 Jul 3, 2022
576b746
Merge branch 'tuplex:master' into master
aletheia094 Jul 13, 2022
4967b98
moved changes to new branch
aletheia094 Jul 13, 2022
6cee06d
added dict case to nassign; need to gdb
aletheia094 Jul 14, 2022
57a36b1
not sure what value_type needs to be for recursive case
aletheia094 Jul 15, 2022
42a2715
typing working for simple function
aletheia094 Jul 18, 2022
601ed05
AST fully typed for simple case
aletheia094 Jul 20, 2022
891441a
added more tests/examples for dict typing
aletheia094 Jul 20, 2022
cf32f57
fixed typing for empty diicts and option case
aletheia094 Jul 22, 2022
02f0d5b
Merge branch 'tuplex:master' into dict-typing
aletheia094 Jul 22, 2022
ce3709a
added dict_keys and dict_values types
aletheia094 Jul 26, 2022
bac5fa8
merging from master Merge branch 'dict-typing' of https://github.com/…
aletheia094 Jul 26, 2022
7be7718
compiles now, emptydict promotion
LeonhardFS Jul 27, 2022
64901a1
stubs
LeonhardFS Jul 27, 2022
d4e1431
fix
LeonhardFS Jul 27, 2022
e94b73f
Merge pull request #1 from aletheia094/dict-typing-fixes
aletheia094 Jul 27, 2022
3936c34
pulled dict proxy files
aletheia094 Jul 27, 2022
510977a
wip
LeonhardFS Jul 28, 2022
b5407eb
pushing so I can write code locally
aletheia094 Jul 31, 2022
607592f
basic tests passing for cJSON dict proxy
aletheia094 Aug 12, 2022
234b591
typing fixes
LeonhardFS Aug 15, 2022
4ecbc9d
adding list conversion
LeonhardFS Aug 15, 2022
662564e
all typing tests pass
LeonhardFS Aug 15, 2022
ce8e25a
Merge pull request #2 from aletheia094/dict-typing-fixes
aletheia094 Aug 16, 2022
d4448b2
all tests except keys/values view failing
aletheia094 Aug 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 90 additions & 44 deletions tuplex/codegen/include/ASTAnnotation.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ class Symbol : public std::enable_shared_from_this<Symbol> {
std::shared_ptr<Symbol> parent;

///! an optional abstract typer function which can be applied if the symboltype is function
///! to deliver a concretely typed type based on the paramter type
std::function<python::Type(const python::Type&)> functionTyper;

///! an optional abstract typer that takes the original type of the caller (e.g., for an attribute)
///! and provides then together with the parameterType symilar to functionTyper a concrete type for the attribute function
std::function<python::Type(const python::Type&,const python::Type&)> attributeFunctionTyper;

///! optionally constant data associated with that symbol
tuplex::Field constantData;

Expand Down Expand Up @@ -90,55 +95,43 @@ class Symbol : public std::enable_shared_from_this<Symbol> {
auto generic_result = functionTyper(parameterType);
if(generic_result != python::Type::UNKNOWN) {
specializedFunctionType = generic_result;

assertFunctionDoesNotReturnGeneric(specializedFunctionType);
return true;
}

for(auto& type : types) {
// found symbol, now check its type
if(!type.isFunctionType())
continue;

auto tupleArgType = getTupleArg(type.getParamsType());
// typer did not yield a result, hence try stored funciton types incl. upcasting
return findStoredTypedFunction(parameterType, specializedFunctionType);
}

// check if there's a direct type match => use that function then!
if(parameterType == tupleArgType) {
specializedFunctionType = type;
assertFunctionDoesNotReturnGeneric(specializedFunctionType);
return true;
}
/*!
* the typing of an attribute which is a function may be based on both the callerType and the parameters. I.e.,
* this function helps to type an attribute x.a(p) where callerType = type(x) and parameterType = type(p) for some
* symbol a which is this.
* @param callerType
* @param parameterType
* @param specializedFunctionType where to store the concrete (non-generic!) output type!
* @return true if a specialized function type could be generated, false else.
*/
inline bool findAttributeFunctionType(const python::Type& callerType,
const python::Type& parameterType,
python::Type& specializedFunctionType) {
// fallback based typing:
// 1. check attribute typer
// 2. check general typer
auto typed_result = attributeFunctionTyper(callerType, parameterType);
if(python::Type::UNKNOWN == typed_result) {
typed_result = functionTyper(parameterType);
}

// no direct match was found. Check whether casting would work or partial matching.
for(auto& type : types) {
// found symbol, now check its type
if (!type.isFunctionType())
continue;

auto tupleArgType = getTupleArg(type.getParamsType());

// check if given parameters type is compatible with function type?
// actual invocation is with parameterType
// ==> can we upcast them to fit the defined one OR does is partially work?
// e.g., when the function is defined for NULL, but we have opt?
if (isTypeCompatible(parameterType, tupleArgType)) {
specializedFunctionType = type;

// specialize according to parameterType if it's a generic function so further typing works
assert(!specializedFunctionType.getReturnType().isGeneric());
if(specializedFunctionType.getParamsType().isGeneric()) {
auto specializedParams = python::specializeGenerics(parameterType, tupleArgType);
specializedFunctionType = python::Type::makeFunctionType(specializedParams,
specializedFunctionType.getReturnType());
}

assertFunctionDoesNotReturnGeneric(specializedFunctionType);
return true;
}
// check if result is valid, then take it
if(typed_result != python::Type::UNKNOWN) {
specializedFunctionType = typed_result;
assertFunctionDoesNotReturnGeneric(specializedFunctionType);
return true;
}

return false;
// typer did not yield a result, hence try stored funciton types incl. upcasting
return findStoredTypedFunction(parameterType, specializedFunctionType);
}

/*!
Expand Down Expand Up @@ -169,7 +162,8 @@ class Symbol : public std::enable_shared_from_this<Symbol> {
return full_name;
}

Symbol() {}
Symbol() : functionTyper([](const python::Type&){return python::Type::UNKNOWN;}),
attributeFunctionTyper([](const python::Type&, const python::Type&){return python::Type::UNKNOWN;}) {}
virtual ~Symbol() {
_attributes.clear();
parent.reset();
Expand Down Expand Up @@ -216,24 +210,76 @@ class Symbol : public std::enable_shared_from_this<Symbol> {

Symbol(std::string _name,
std::function<python::Type(const python::Type&)> typer) : name(_name), qualifiedName(_name),
functionTyper(std::move(typer)), symbolType(SymbolType::FUNCTION) {}
functionTyper(std::move(typer)), attributeFunctionTyper([](const python::Type&, const python::Type&){return python::Type::UNKNOWN;}), symbolType(SymbolType::FUNCTION) {}

Symbol(std::string _name, python::Type _type) : name(_name), qualifiedName(_name),
types{_type},
symbolType(_type.isFunctionType() ? SymbolType::FUNCTION : SymbolType::VARIABLE), functionTyper([](const python::Type&) { return python::Type::UNKNOWN; }) {}
symbolType(_type.isFunctionType() ? SymbolType::FUNCTION : SymbolType::VARIABLE),
functionTyper([](const python::Type&) { return python::Type::UNKNOWN; }),
attributeFunctionTyper([](const python::Type&, const python::Type&){return python::Type::UNKNOWN;}) {}

Symbol(std::string _name, std::string _qualifiedName, python::Type _type, SymbolType _symbolType) : name(_name),
qualifiedName(_qualifiedName),
types{_type},
symbolType(_symbolType),
functionTyper([](const python::Type&) { return python::Type::UNKNOWN; }) {}
functionTyper([](const python::Type&) { return python::Type::UNKNOWN; }),
attributeFunctionTyper([](const python::Type&, const python::Type&){return python::Type::UNKNOWN;}) {}

private:
///! i.e. to store something like re.search. re is then of module type. search will have a concrete function type.
std::vector<std::shared_ptr<Symbol>> _attributes;

/********* HELPER FUNCTIONS *************/

inline bool findStoredTypedFunction(const python::Type& parameterType, python::Type& specializedFunctionType) {

// typing using typer functions above failed, hence now search for concrete stored types.
for(auto& type : types) {
// found symbol, now check its type
if(!type.isFunctionType())
continue;

auto tupleArgType = getTupleArg(type.getParamsType());

// check if there's a direct type match => use that function then!
if(parameterType == tupleArgType) {
specializedFunctionType = type;
assertFunctionDoesNotReturnGeneric(specializedFunctionType);
return true;
}
}

// no direct match was found. Check whether casting would work or partial matching.
for(auto& type : types) {
// found symbol, now check its type
if (!type.isFunctionType())
continue;

auto tupleArgType = getTupleArg(type.getParamsType());

// check if given parameters type is compatible with function type?
// actual invocation is with parameterType
// ==> can one upcast them to fit the defined one OR does is partially work?
// e.g., when the function is defined for NULL, but we have opt?
if (isTypeCompatible(parameterType, tupleArgType)) {
specializedFunctionType = type;

// specialize according to parameterType if it's a generic function so further typing works
assert(!specializedFunctionType.getReturnType().isGeneric());
if(specializedFunctionType.getParamsType().isGeneric()) {
auto specializedParams = python::specializeGenerics(parameterType, tupleArgType);
specializedFunctionType = python::Type::makeFunctionType(specializedParams,
specializedFunctionType.getReturnType());
}

assertFunctionDoesNotReturnGeneric(specializedFunctionType);
return true;
}
}

return false;
}

/*!
* helper function to check for compatibility, i.e. whether from type can be cast to to type.
* @param from source type
Expand Down
2 changes: 1 addition & 1 deletion tuplex/codegen/include/AnnotatedAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ namespace tuplex {

/*!
* annotates the tree with final types. If this is not possible, returns false
* @param pokicy compiler policy
* @param policy compiler policy
* @param silentMode determines whether the type inference should log out problems or not
* @param removeBranches whether to use RemoveDeadBranchesVisitor to prune AST
* @return whether types could be successfully annotated/defined for all AST nodes
Expand Down
90 changes: 90 additions & 0 deletions tuplex/codegen/include/BuiltinDictProxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//--------------------------------------------------------------------------------------------------------------------//
// //
// Tuplex: Blazing Fast Python Data Science //
// //
// //
// (c) 2017 - 2021, Tuplex team //
// Created by Leonhard Spiegelberg first on 8/9/2021 //
// License: Apache 2.0 //
//--------------------------------------------------------------------------------------------------------------------//
#ifndef TUPLEX_BUILTINDICTPROXY_H
#define TUPLEX_BUILTINDICTPROXY_H

#include <memory>

#include <TypeSystem.h>
#include <BuiltinDictProxyImpl.h>
#include <cJSONDictProxyImpl.h>

// TODO: Could also use a general object based system which would make things easier...
// -> i.e., sequence protocol strings/lists/...

// basically for each object we need
// 1.) representation as C++ object (field)
// 2.) code-generated logic (i.e., codegen specialization)
// 3.) to/from python object

namespace tuplex {
namespace codegen {
class BuiltinDictProxy {
public:
// BuiltinDictProxy (--> specializedDictType)
BuiltinDictProxy(const python::Type& specializedDictType) : _specializedType(specializedDictType) {
// use cJSON as default for now...
_impl = std::make_shared<cJSONDictProxyImpl>();
}

// use both codegen/non-codegen version
// putItem
BuiltinDictProxy& putItem(const Field& key, const Field& value) { assert(_impl); _impl->putItem(key, value); return *this; }
BuiltinDictProxy& putItem(const python::Type& keyType, const SerializableValue& key, const python::Type& valueType, const SerializableValue& value) { assert(_impl); _impl->putItem(keyType, key, valueType, value); return *this; }

// // getItem
// BuiltinDictProxy& getItem(const Field& key);
// BuiltinDictProxy& getItem(const python::Type& keyType, const SerializableValue& key);
//
// // delItem
// BuiltinDictProxy& delItem(const Field& key);
// BuiltinDictProxy& delItem(const python::Type& keyType, const SerializableValue& key);
//
// // allocSize() --> helpful when dict size is known upfront, can be used for optimization.
// BuiltinDictProxy& allocSize(llvm::Value* size);

// getKeysView() --> codegen object

// getValuesView() --> codegen object

python::Type dictType() const {
throw std::runtime_error("not yet implemented");
}

python::Type specializedDictType() const {
return _specializedType;
}

// codegenToMemory

// codegenFromMemory
// static function?

// codegenSerializedLength

// toMemory

// fromMemory
// static function?

// serializedLength
private:
python::Type _specializedType;

// implementation...
// -> cJSON
// -> ...
// -> ...
std::shared_ptr<BuiltinDictProxyImpl> _impl;
};
}
}

#endif //TUPLEX_BUILTINDICTPROXY_H
40 changes: 40 additions & 0 deletions tuplex/codegen/include/BuiltinDictProxyImpl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//--------------------------------------------------------------------------------------------------------------------//
// //
// Tuplex: Blazing Fast Python Data Science //
// //
// //
// (c) 2017 - 2021, Tuplex team //
// Created by Leonhard Spiegelberg first on 8/9/2021 //
// License: Apache 2.0 //
//--------------------------------------------------------------------------------------------------------------------//

#ifndef TUPLEX_BUILTINDICTPROXYIMPL_H
#define TUPLEX_BUILTINDICTPROXYIMPL_H

#include <TypeSystem.h>
#include <Row.h>
#include <CodegenHelper.h>

namespace tuplex {
namespace codegen {
class BuiltinDictProxyImpl {
public:
virtual void putItem(const Field& key, const Field& value) = 0;
virtual void putItem(const python::Type& keyType, const SerializableValue& key, const python::Type& valueType, const SerializableValue& value) = 0;

virtual bool keyExists(const Field& key) = 0;

virtual Field getItem(const Field& key) = 0;

virtual void replaceItem(const Field& key, const Field& value) = 0;

virtual void deleteItem(const Field& key) = 0;

virtual std::vector<Field> getKeysView() = 0;

virtual std::vector<Field> getValuesView() = 0;
};
}
}

#endif //TUPLEX_BUILTINDICTPROXYIMPL_H
31 changes: 29 additions & 2 deletions tuplex/codegen/include/SymbolTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,36 @@ namespace tuplex {
* add an attribute to a builtin type, e.g. str.lower
* @param builtinType
* @param name
* @param type
* @param type type of the attribute, i.e. if it is a function type then a function symbol will be added.
* If it is not a function type a variable symbol will be added.
*/
void addBuiltinTypeAttribute(const python::Type& builtinType,
const std::string& name,
const python::Type& type);

/*!
* add an attribute to a builtin type, e.g. dict.keys()
* @param builtinType to which type to add the function
* @param name name of the attribute
* @param typer a dynamic typing function
* @param sym_type what kind of symbol it is (function? variable?), needed because typer works for both.
*/
void addBuiltinTypeAttribute(const python::Type& builtinType,
const std::string& name,
std::function<python::Type(const python::Type&)> typer,
const SymbolType& sym_type);

/*!
* add an attribute to a builtin type, e.g. dict.keys()
* @param builtinType to which type to add the function
* @param name name of the attribute
* @param typer a dynamic typing function
* @param sym_type what kind of symbol it is (function? variable?), needed because typer works for both.
*/
void addBuiltinTypeAttribute(const python::Type& builtinType, const std::string& name, const python::Type& type);
void addBuiltinTypeAttribute(const python::Type& builtinType,
const std::string& name,
std::function<python::Type(const python::Type&, const python::Type&)> attributeTyper,
const SymbolType& sym_type=SymbolType::FUNCTION);

/*!
* checks whether a symbol can be looked up or not
Expand Down
4 changes: 4 additions & 0 deletions tuplex/codegen/include/TypeAnnotatorVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ namespace tuplex {
const TokenType tt, ASTNode* right,
const python::Type& b);
void assignHelper(NIdentifier *id, python::Type type);

bool is_nested_subscript_target(ASTNode* target);
void recursive_set_subscript_types(NSubscription* target, python::Type value_type);

void checkRetType(python::Type t);
/*!
* Annotate iterator-related NCall with iterator-specific info
Expand Down
Loading