Permalink
Browse files

Fixed a bug with function type inference in recursive functions. Adde…

…d "factorial" example (see test/test_factorial.hue)
  • Loading branch information...
1 parent 52aa254 commit 94441d9b31157d712c078faa63c741d78ca3fba2 @rsms committed May 29, 2012
View
@@ -199,7 +199,8 @@ test_lang: test_lang_data_literals \
test_lang_conditionals \
test_lang_funcs \
test_func_inferred_result_type \
- test_func_fib
+ test_func_fib \
+ test_factorial
test_lang_data_literals: test_lang_deps
bash -c '$(build_bin_dir)/hue test/test_lang_data_literals.hue | grep "Hello World" >/dev/null || exit 1'
@@ -211,14 +212,17 @@ test_lang_conditionals: test_lang_deps
$(build_bin_dir)/hue test/test_lang_conditionals.hue
test_lang_funcs: test_lang_deps
- $(build_bin_dir)/hue test/test_lang_funcs.hue
+ bash -c '$(build_bin_dir)/hue test/test_lang_funcs.hue >/dev/null || exit 1'
test_func_inferred_result_type: test_lang_deps
bash -c '$(build_bin_dir)/hue test/test_func_inferred_result_type.hue | grep "45.900000 2 2.000000" >/dev/null || exit 1'
test_func_fib: test_lang_deps
bash -c '$(build_bin_dir)/hue test/test_func_fib.hue | grep "2178309" >/dev/null || exit 1'
+test_factorial: test_lang_deps
+ bash -c '$(build_bin_dir)/hue test/test_factorial.hue | grep "3628800 3628800.0" >/dev/null || exit 1'
+
# test/build/X <- test/X.cc
$(test_build_dir)/%: test/%.cc
$(CXXC) $(CFLAGS) $(CXXFLAGS) $(libhuert_cxx_flags) $(libhuert_ld_flags) -o $@ $<
View
@@ -27,6 +27,22 @@ Objectives and plans:
Seriously, this is just for fun. Don't expect anything from this project.
+## Examples
+
+fib.hue
+
+ fib = func (n Int)
+ if n < 2
+ n
+ else
+ (fib n-1) + fib n-2
+
+ fib 32 # -> 2178309
+
+factorial.hue
+
+
+
## Building
First, you need to grab and build llvm. See `deps/llvm/README` for details.
View
@@ -39,7 +39,7 @@ std::string mangle(const ast::FunctionType& funcType) {
ast::VariableList* args = funcType.args();
if (args) mname += mangle(*args);
mname += '$';
- ast::Type* returnType = funcType.resultType();
+ const ast::Type* returnType = funcType.resultType();
if (returnType) mname += mangle(*returnType);
return mname;
}
View
@@ -28,7 +28,7 @@ class BinaryOp : public Expression {
Expression *lhs() const { return lhs_; }
Expression *rhs() const { return rhs_; }
- virtual Type *resultType() const {
+ virtual const Type *resultType() const {
if (isComparison()) {
return resultType_; // always Type::Bool
} else if (!lhs_->resultType()->isUnknown()) {
@@ -38,7 +38,7 @@ class BinaryOp : public Expression {
}
}
- virtual void setResultType(Type* T) {
+ virtual void setResultType(const Type* T) {
assert(T->isUnknown() == false); // makes no sense to set T=unknown
// Call setResultType with T for LHS and RHS which are unknown
if (lhs_ && lhs_->resultType()->isUnknown()) {
View
@@ -18,18 +18,18 @@ class Block : public Expression {
const ExpressionList& expressions() const { return expressions_; };
void addExpression(Expression *expression) { expressions_.push_back(expression); };
- virtual Type *resultType() const {
+ virtual const Type *resultType() const {
if (expressions_.size() != 0) {
return expressions_.back()->resultType();
} else {
return resultType_; // Type::Unknown
}
}
- virtual void setResultType(Type* T) {
+ virtual void setResultType(const Type* T) {
assert(T->isUnknown() == false); // makes no sense to set T=unknown
// Call setResultType with T for last expression if the last expression is unknown
- if (expressions_.size() != 0 && expressions_.back()->resultType()->isUnknown()) {
+ if (expressions_.size() != 0) {
expressions_.back()->setResultType(T);
}
}
View
@@ -23,15 +23,15 @@ class Call : public Expression {
Function* callee() const { return callee_; }
void setCallee(Function* F) { callee_ = F; }
- virtual Type *resultType() const {
+ virtual const Type *resultType() const {
if (callee_ != 0) {
- return callee_->resultType();
+ return callee_->resultType() ? callee_->resultType() : &UnknownType;
} else {
return resultType_; // Type::Unknown
}
}
- virtual void setResultType(Type* T) {
+ virtual void setResultType(const Type* T) {
assert(T->isUnknown() == false); // makes no sense to set T=unknown
// Call setResultType with T for callee if callee's resultType is unknown
if (callee_ && callee_->resultType()->isUnknown()) {
View
@@ -23,32 +23,34 @@ class Conditional : public Expression {
Block* falseBlock() const { return falseBlock_; }
void setFalseBlock(Block* B) { falseBlock_ = B; }
- virtual Type *resultType() const {
+ virtual const Type *resultType() const {
assert(trueBlock_);
- Type* BT = trueBlock_->resultType();
- if (BT && !BT->isUnknown())
- return BT;
+ const Type* trueT = trueBlock_->resultType();
+ const Type* falseT = falseBlock_->resultType();
- assert(falseBlock_);
- BT = falseBlock_->resultType();
- if (BT && !BT->isUnknown())
- return BT;
-
- return resultType_; // Type::Unknown
+ if (trueT && !trueT->isUnknown() && falseT && !falseT->isUnknown()) {
+ // Return the highest fidelity type
+ const Type* T = Type::highestFidelity(trueT, falseT);
+ if (T == 0) {
+ // The types are different in a way where neither is better (e.g. int vs func)
+ return resultType_; // Type::Unknown
+ } else {
+ return T;
+ }
+ } else if (trueT && !trueT->isUnknown()) {
+ return trueT;
+ } else if (falseT && !falseT->isUnknown()) {
+ return falseT;
+ } else {
+ return resultType_; // Type::Unknown
+ }
}
- virtual void setResultType(Type* T) {
+ virtual void setResultType(const Type* T) {
assert(trueBlock_);
- Type* BT = trueBlock_->resultType();
- if (!BT || BT->isUnknown()) {
- trueBlock_->setResultType(T);
- }
-
+ trueBlock_->setResultType(T);
assert(falseBlock_);
- BT = falseBlock_->resultType();
- if (!BT || BT->isUnknown()) {
- falseBlock_->setResultType(T);
- }
+ falseBlock_->setResultType(T);
}
virtual std::string toString(int level = 0) const {
View
@@ -29,13 +29,9 @@ class Expression : public Node {
virtual ~Expression() {}
// Type of result from this expression
- virtual Type *resultType() const { return resultType_; }
- virtual void setResultType(Type* T) {
- if (resultType_ != T) {
- Type* OT = resultType_;
- resultType_ = T;
- if (OT) delete OT;
- }
+ virtual const Type *resultType() const { return resultType_; }
+ virtual void setResultType(const Type* T) {
+ resultType_ = T;
}
virtual std::string toString(int level = 0) const {
@@ -45,7 +41,7 @@ class Expression : public Node {
}
protected:
- Type* resultType_;
+ const Type* resultType_;
};
// Numeric integer literals like "3".
@@ -102,15 +98,15 @@ class Assignment : public Expression {
const Variable* variable() const { return var_; };
Expression* rhs() const { return rhs_; }
- virtual Type *resultType() const {
+ virtual const Type *resultType() const {
if (rhs_ && var_->hasUnknownType()) {
return rhs_->resultType();
} else {
return var_->type();
}
}
- virtual void setResultType(Type* T) throw(std::logic_error) {
+ virtual void setResultType(const Type* T) throw(std::logic_error) {
throw std::logic_error("Can not set type for compound 'Assignment' expression");
}
View
@@ -36,13 +36,9 @@ class FunctionType : public Node {
VariableList *args() const { return args_; }
- Type *resultType() const { return resultType_; }
- void setResultType(Type* T) {
- if (resultType_ != T) {
- Type* OT = resultType_;
- resultType_ = T;
- if (OT) delete OT;
- }
+ const Type *resultType() const { return resultType_; }
+ void setResultType(const Type* T) {
+ resultType_ = T;
}
bool resultTypeIsUnknown() const { return resultType_ && resultType_->isUnknown(); }
@@ -95,7 +91,7 @@ class FunctionType : public Node {
private:
VariableList *args_;
- Type *resultType_;
+ const Type *resultType_;
bool isPublic_;
};
@@ -113,10 +109,10 @@ class Function : public Expression {
Block *body() const { return body_; }
// Override Expression result type
- virtual Type *resultType() const {
+ virtual const Type *resultType() const {
return functionType_ ? functionType_->resultType() : 0;
}
- virtual void setResultType(Type* T) {
+ virtual void setResultType(const Type* T) {
if (functionType_) functionType_->setResultType(T);
}
@@ -145,10 +141,10 @@ class ExternalFunction : public Expression {
inline FunctionType *functionType() const { return functionType_; }
// Override Expression result type
- virtual Type *resultType() const {
+ virtual const Type *resultType() const {
return functionType_ ? functionType_->resultType() : 0;
}
- virtual void setResultType(Type* T) {
+ virtual void setResultType(const Type* T) {
if (functionType_) functionType_->setResultType(T);
}
View
@@ -4,7 +4,7 @@
namespace hue { namespace ast {
-Type *Symbol::resultType() const {
+const Type *Symbol::resultType() const {
if (value_ && value_->isExpression()) {
return static_cast<Expression*>(value_)->resultType();
} else if (value_ && value_->isFunctionType()) {
@@ -17,7 +17,7 @@ Type *Symbol::resultType() const {
}
}
-void Symbol::setResultType(Type* T) {
+void Symbol::setResultType(const Type* T) {
assert(T->isUnknown() == false); // makes no sense to set T=unknown
// Call setResultType with T for value_ if value_ result type is unknown
if (value_) {
View
@@ -21,9 +21,9 @@ class Symbol : public Expression {
Node* value() const { return value_; }
void setValue(Node* value) { value_ = value; }
- virtual Type *resultType() const;
+ virtual const Type *resultType() const;
- virtual void setResultType(Type* T);
+ virtual void setResultType(const Type* T);
virtual std::string toString(int level = 0) const {
std::ostringstream ss;
View
@@ -0,0 +1,9 @@
+// Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source
+// code is governed by a MIT-style license that can be found in the LICENSE file.
+#include "Type.h"
+
+namespace hue { namespace ast {
+
+//const Type UnknownType(Type::Unknown);
+
+}} // namespace hue::ast
View
@@ -44,6 +44,8 @@ class Type {
inline bool isUnknown() const { return typeID_ == Unknown; }
inline bool isFunction() const { return typeID_ == Func; }
+ inline bool isInt() const { return typeID_ == Int; }
+ inline bool isFloat() const { return typeID_ == Float; }
virtual std::string toString() const {
switch (typeID_) {
@@ -59,12 +61,27 @@ class Type {
}
virtual std::string toHueSource() const { return toString(); }
+
+ static const Type* highestFidelity(const Type* T1, const Type* T2) {
+ if (T1 == T2 || T1->isEqual(*T2)) {
+ return T1;
+ } else if (T1->isInt() && T2->isFloat()) {
+ return T2;
+ } else if (T2->isInt() && T1->isFloat()) {
+ return T1;
+ } else {
+ // Unknown
+ return 0;
+ }
+ }
private:
TypeID typeID_;
Text name_;
};
+static const Type UnknownType(Type::Unknown);
+
class ArrayType : public Type {
public:
View
@@ -24,9 +24,9 @@ class Variable : public Node {
const bool& isMutable() const { return isMutable_; }
const Text& name() const { return name_; }
- Type *type() const { return type_; }
+ const Type *type() const { return type_; }
bool hasUnknownType() const { return !type_ || type_->typeID() == Type::Unknown; }
- void setType(Type *type) { type_ = type; }
+ void setType(const Type *type) { type_ = type; }
std::string toString(int level = 0) const {
std::ostringstream ss;
@@ -42,7 +42,7 @@ class Variable : public Node {
private:
bool isMutable_;
Text name_;
- Type *type_;
+ const Type *type_;
};
View
@@ -352,7 +352,7 @@ class Visitor {
llvm::Value *codegenBlock(const ast::Block *block);
llvm::Value *codegenAssignment(const ast::Assignment* node);
- llvm::Value *codegenCall(const ast::Call* node, ast::Type* expectedReturnType = 0);
+ llvm::Value *codegenCall(const ast::Call* node, const ast::Type* expectedReturnType = 0);
llvm::Value *codegenConditional(const ast::Conditional* node);
llvm::Value *codegenIntLiteral(const ast::IntLiteral *literal, bool fixedSize = true);
llvm::Value *codegenFloatLiteral(const ast::FloatLiteral *literal, bool fixedSize = true);
View
@@ -19,11 +19,11 @@ Value *Visitor::codegenBinaryOp(const ast::BinaryOp *binOpExp) {
// Numbers: cast to richest type if needed
if (LT->isIntegerTy() && RT->isDoubleTy()) {
// Cast L to double
- rlog("Binop: Cast LHS to double");
+ //rlog("Binop: Cast LHS to double");
L = builder_.CreateSIToFP(L, (type = RT), "itoftmp");
} else if (LT->isDoubleTy() && RT->isIntegerTy()) {
// Cast R to double
- rlog("Binop: Cast RHS to double. LHS -> "); L->dump();
+ //rlog("Binop: Cast RHS to double. LHS -> "); L->dump();
R = builder_.CreateSIToFP(R, (type = LT), "itoftmp");
}
Oops, something went wrong.

0 comments on commit 94441d9

Please sign in to comment.