* use typevar function

* lift lambda classes to the block, not the classbody

* use node to token comparison

* WIP, need to lift lambdas earlier

* change all dir::once passes to bottomup

* pick up trieste performance improvements

* move conditionals pass earlier

* detect bad default args early

* separate reference and typereference

* move the lambda pass earlier

* move autocreate and defaultargs earlier

* fix defaultargs param order

* remove symtab from Block

* discard std::equal result as a pairwise check

* capture param type before error is emitted
This commit is contained in:
Sylvan Clebsch 2023-09-26 05:46:37 +01:00 коммит произвёл GitHub
Родитель 5b548e01a1
Коммит 5d6a8a72a2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
39 изменённых файлов: 1420 добавлений и 945 удалений

Просмотреть файл

@ -6,16 +6,18 @@ add_executable(verona
subtype.cc
passes/modules.cc
passes/structure.cc
passes/memberconflict.cc
passes/conditionals.cc
passes/reference.cc
passes/typenames.cc
passes/typeview.cc
passes/typefunc.cc
passes/typealg.cc
passes/typeflat.cc
passes/typevalid.cc
passes/typereference.cc
passes/codereuse.cc
passes/conditionals.cc
passes/reference.cc
passes/memberconflict.cc
passes/resetimplicit.cc
passes/reverseapp.cc
passes/application.cc
passes/assignlhs.cc
@ -33,6 +35,7 @@ add_executable(verona
passes/defbeforeuse.cc
passes/drop.cc
passes/validtypeargs.cc
passes/typeinfer.cc
)
target_precompile_headers(verona

Просмотреть файл

@ -23,11 +23,11 @@ namespace verona
while (true)
{
if (node->type().in({Type, TypePred}))
if (node->in({Type, TypePred}))
{
node = node / Type;
}
else if (node->type().in({FQType, FQFunction}))
else if (node->in({FQType, FQFunction}))
{
auto lookup = resolve_fq(node);
@ -45,7 +45,7 @@ namespace verona
if (set.contains(node))
return;
}
else if (node->type() == TypeParam)
else if (node == TypeParam)
{
set.insert(node);
auto it = bindings.find(node);
@ -85,16 +85,16 @@ namespace verona
return make(t, bindings);
}
Btype field(const Token& f)
{
return make(node / f, bindings);
}
const Token& type() const
{
return node->type();
}
bool in(const std::initializer_list<Token>& list) const
{
return node->in(list);
}
void str(std::ostream& out, size_t level)
{
out << indent(level) << "btype: {" << std::endl;
@ -102,7 +102,7 @@ namespace verona
// Print the node.
out << indent(level + 1) << "node: {" << std::endl;
if (node->type().in({Class, TypeAlias, Function}))
if (node->in({Class, TypeAlias, Function}))
{
out << indent(level + 2) << node->type().str() << " "
<< (node / Ident)->location().view();
@ -136,6 +136,16 @@ namespace verona
return BtypeDef::make(t, {});
}
inline Btype operator/(Btype& b, const Token& f)
{
return b->make(b->node / f);
}
inline bool operator==(const Btype& b, const Token& type)
{
return b->type() == type;
}
inline std::ostream& operator<<(std::ostream& out, const Btype& b)
{
b->str(out, 0);

Просмотреть файл

@ -13,9 +13,19 @@ namespace verona
return Error << (ErrorMsg ^ msg) << node;
}
Node typevar(Location loc)
{
return Type << (TypeVar ^ loc);
}
Node typevar(Node& node)
{
return typevar(node->fresh(l_typevar));
}
Node typevar(Match& _)
{
return Type << (TypeVar ^ _.fresh(l_typevar));
return typevar(_.fresh(l_typevar));
}
Node typevar(Match& _, const Token& t)
@ -59,37 +69,83 @@ namespace verona
<< (TypeClassName << (Ident ^ l_builtin) << TypeArgs);
}
static Node builtin_type(const Location& name, Node ta = TypeArgs)
{
return FQType << builtin_path() << (TypeClassName << (Ident ^ name) << ta);
}
static Node call0(Node type, const Location& loc)
{
return call(FQFunction << type << selector(loc));
}
static Node create0(Node type)
{
return call0(type, l_create);
}
Node nonlocal(Match& _)
{
// Pin the type argument to a specific type variable.
static Location l_nonlocal("nonlocal");
return FQType << builtin_path()
<< (TypeClassName << (Ident ^ l_nonlocal)
<< (TypeArgs << typevar(_)));
return builtin_type(l_nonlocal, TypeArgs << typevar(_));
}
Node unittype()
{
static Location l_unit("unit");
return FQType << builtin_path()
<< (TypeClassName << (Ident ^ l_unit) << TypeArgs);
return builtin_type(l_unit);
}
Node unit()
{
return call(FQFunction << unittype() << selector(l_create));
return create0(unittype());
}
Node booltype()
{
static Location l_bool("Bool");
return builtin_type(l_bool);
}
Node booltrue()
{
static Location l_true("make_true");
return call0(booltype(), l_true);
}
Node boolfalse()
{
static Location l_false("make_false");
return call0(booltype(), l_false);
}
Node celltype()
{
static Location l_cell("cell");
return FQType << builtin_path()
<< (TypeClassName << (Ident ^ l_cell) << TypeArgs);
static Location l_cell("Cell");
return builtin_type(l_cell);
}
Node cell()
{
return call(FQFunction << celltype() << selector(l_create));
return create0(celltype());
}
Node reftype(Node t)
{
static Location l_ref("Ref");
return builtin_type(l_ref, TypeArgs << -t);
}
Node tuple_to_args(Node n)
{
assert(n == Tuple);
if (n->size() == 0)
return Unit;
else if (n->size() == 1)
return n->front();
else
return n;
}
Node selector(Node name, Node ta)
@ -109,119 +165,101 @@ namespace verona
{
// `op` must already be in the AST in order to resolve the FQFunction.
// If not, it won't be treated as an LLVM call.
if (op->type() != FQFunction)
if (op != FQFunction)
return false;
auto l = resolve_fq(op);
return l.def && (l.def->type() == Function) &&
((l.def / LLVMFuncType)->type() == LLVMFuncType);
return l.def && (l.def == Function) &&
((l.def / LLVMFuncType) == LLVMFuncType);
}
static Node arg(Node args, Node arg)
{
if (arg)
{
if (arg->type() == Tuple)
if (arg == Tuple)
args->push_back({arg->begin(), arg->end()});
else if (arg->type() == Expr)
else if (arg == Expr)
args << arg;
else if (arg->type() != Unit)
else if (arg != Unit)
args << (Expr << arg);
}
return args;
}
Node call(Node op, Node lhs, Node rhs, bool post_nlr)
Node call(Node op, Node lhs, Node rhs)
{
assert(op->type().in({FQFunction, Selector}));
assert(op->in({FQFunction, Selector}));
auto args = arg(arg(Args, lhs), rhs);
auto arity = Int ^ std::to_string(args->size());
if (op->type() == FQFunction)
if (op == FQFunction)
(op / Selector / Int) = arity;
else
(op / Int) = arity;
auto ret = Call << op << args;
if (!post_nlr)
ret = NLRCheck << Explicit << ret;
return ret;
return NLRCheck << (Call << op << args);
}
Node call_lhs(Node call)
{
assert(call->type() == Call);
assert(call == Call);
auto f = call / Selector;
if (f->type() == FQFunction)
if (f == FQFunction)
f = f / Selector;
(f / Ref) = Lhs;
return call;
}
Node load(Node arg, bool post_nlr)
Node load(Node arg)
{
static Location l_load("load");
return call(selector(l_load), arg, {}, post_nlr);
return call(selector(l_load), arg);
}
bool is_implicit(Node n)
{
auto f = n->parent(Function);
return f && ((f / Implicit)->type() == Implicit);
return f && ((f / Implicit) == Implicit);
}
static Token handed(Node& node)
{
assert(node->type().in({FieldLet, FieldVar, Function}));
assert(node->in({FieldLet, FieldVar, Function}));
// Return Op to mean both.
if (node->type() == FieldVar)
if (node == FieldVar)
return Op;
else if (node->type() == FieldLet)
else if (node == FieldLet)
return Lhs;
else
return (node / Ref)->type();
}
static std::pair<size_t, size_t> arity(Node& node)
static size_t arity(Node& node)
{
assert(node->type().in({FieldLet, FieldVar, Function}));
if (node->type() != Function)
return {1, 1};
auto params = node / Params;
auto arity_hi = params->size();
auto arity_lo = arity_hi;
for (auto& param : *params)
{
if ((param / Default)->type() != DontCare)
arity_lo--;
}
return {arity_lo, arity_hi};
assert(node->in({FieldLet, FieldVar, Function}));
return (node == Function) ? (node / Params)->size() : 1;
}
bool conflict(Node& a, Node& b)
{
// Check for handedness overlap.
assert(a->in({FieldLet, FieldVar, Function}));
assert(b->in({FieldLet, FieldVar, Function}));
// Check for handedness conflict.
auto a_hand = handed(a);
auto b_hand = handed(b);
if ((a_hand != b_hand) && (a_hand != Op) && (b_hand != Op))
return false;
// Check for arity overlap.
auto [a_lo, a_hi] = arity(a);
auto [b_lo, b_hi] = arity(b);
return (b_hi >= a_lo) && (a_hi >= b_lo);
// Check for arity conflict.
return arity(a) == arity(b);
}
Options& options()
@ -240,33 +278,36 @@ namespace verona
{
{"modules", modules(), wfPassModules},
{"structure", structure(), wfPassStructure},
{"reference", reference(), wfPassReference},
{"conditionals", conditionals(), wfPassConditionals},
{"lambda", lambda(), wfPassLambda},
{"autocreate", autocreate(), wfPassLambda},
{"defaultargs", defaultargs(), wfPassDefaultArgs},
{"typenames", typenames(), wfPassTypeNames},
{"typeview", typeview(), wfPassTypeView},
{"typefunc", typefunc(), wfPassTypeFunc},
{"typealg", typealg(), wfPassTypeAlg},
{"typeflat", typeflat(), wfPassTypeFlat},
{"typevalid", typevalid(), wfPassTypeFlat},
{"reference", reference(), wfPassReference},
{"codereuse", codereuse(), wfPassReference},
{"memberconflict", memberconflict(), wfPassReference},
{"conditionals", conditionals(), wfPassConditionals},
{"typereference", typereference(), wfPassTypeReference},
{"codereuse", codereuse(), wfPassTypeReference},
{"memberconflict", memberconflict(), wfPassTypeReference},
{"resetimplicit", resetimplicit(), wfPassResetImplicit},
{"reverseapp", reverseapp(), wfPassReverseApp},
{"application", application(), wfPassApplication},
{"assignlhs", assignlhs(), wfPassAssignLHS},
{"localvar", localvar(), wfPassLocalVar},
{"assignment", assignment(), wfPassAssignment},
{"lambda", lambda(), wfPassLambda},
{"autofields", autofields(), wfPassAutoFields},
{"autorhs", autorhs(), wfPassAutoFields},
{"autocreate", autocreate(), wfPassAutoCreate},
{"defaultargs", defaultargs(), wfPassDefaultArgs},
{"partialapp", partialapp(), wfPassDefaultArgs},
{"traitisect", traitisect(), wfPassDefaultArgs},
{"partialapp", partialapp(), wfPassAutoFields},
{"traitisect", traitisect(), wfPassAutoFields},
{"nlrcheck", nlrcheck(), wfPassNLRCheck},
{"anf", anf(), wfPassANF},
{"defbeforeuse", defbeforeuse(), wfPassANF},
{"drop", drop(), wfPassDrop},
{"validtypeargs", validtypeargs(), wfPassDrop},
// {"typeinfer", typeinfer(), wfPassDrop},
});
return d;

Просмотреть файл

@ -23,8 +23,10 @@ namespace verona
inline const auto DoubleColon = TokenDef("doublecolon");
inline const auto TripleColon = TokenDef("triplecolon");
inline const auto Arrow = TokenDef("arrow");
inline const auto Bool = TokenDef("bool", flag::print);
inline const auto True = TokenDef("true");
inline const auto False = TokenDef("false");
inline const auto Hex = TokenDef("hex", flag::print);
inline const auto Oct = TokenDef("oct", flag::print);
inline const auto Bin = TokenDef("bin", flag::print);
inline const auto Int = TokenDef("int", flag::print);
inline const auto HexFloat = TokenDef("hexfloat", flag::print);
@ -74,8 +76,7 @@ namespace verona
TokenDef("valueparam", flag::lookup | flag::lookdown | flag::shadowing);
inline const auto Params = TokenDef("params");
inline const auto Param = TokenDef("param", flag::lookup | flag::shadowing);
inline const auto Block =
TokenDef("block", flag::symtab | flag::defbeforeuse);
inline const auto Block = TokenDef("block");
// Type structure.
inline const auto Type = TokenDef("type");
@ -138,43 +139,74 @@ namespace verona
// Rewrite identifiers.
inline const auto Implicit = TokenDef("implicit");
inline const auto Explicit = TokenDef("explicit");
inline const auto Lhs = TokenDef("Lhs");
inline const auto Rhs = TokenDef("Rhs");
inline const auto Op = TokenDef("Op");
inline const auto LambdaFunc = TokenDef("lambdafunc");
inline const auto Lhs = TokenDef("lhs");
inline const auto Rhs = TokenDef("rhs");
inline const auto Op = TokenDef("op");
// Sythetic locations.
inline const auto l_typevar = Location("typevar");
inline const auto l_param = Location("param");
inline const auto l_trait = Location("trait");
inline const auto l_class = Location("class");
inline const auto l_objlit = Location("objlit");
inline const auto l_lambda = Location("lambda");
inline const auto l_self = Location("self");
inline const auto l_new = Location("new");
inline const auto l_apply = Location("apply");
inline const auto l_create = Location("create");
// Helper patterns.
inline const auto IsImplicit = T(Implicit) / T(Explicit);
inline const auto Hand = T(Lhs) / T(Rhs);
inline const auto TypeStruct = In(Type) / In(TypeList) / In(TypeTuple) /
In(TypeView) / In(TypeUnion) / In(TypeIsect) / In(TypeSubtype);
inline const auto TypeCaps = T(Iso) / T(Mut) / T(Imm);
inline const auto Literal = T(String) / T(Escaped) / T(Char) / T(Bool) /
T(Hex) / T(Bin) / T(Int) / T(Float) / T(HexFloat) / T(LLVM);
inline const auto TypeElem = T(Type) / TypeCaps / T(FQType) / T(Trait) /
T(TypeTuple) / T(Self) / T(TypeList) / T(TypeView) / T(TypeIsect) /
T(TypeUnion) / T(TypeVar) / T(Package) / T(TypeSubtype) / T(TypeTrue) /
T(TypeFalse);
inline const auto Object0 = Literal / T(RefVar) / T(RefVarLHS) / T(RefLet) /
T(Unit) / T(Tuple) / T(Lambda) / T(Call) / T(NLRCheck) / T(Assign) /
T(Expr) / T(ExprSeq) / T(DontCare) / T(Conditional) / T(TypeTest) / T(Cast);
inline const auto IsImplicit = T(Implicit, Explicit, LambdaFunc);
inline const auto Hand = T(Lhs, Rhs);
inline const auto TypeStruct =
In(Type, TypeList, TypeTuple, TypeView, TypeUnion, TypeIsect, TypeSubtype);
inline const auto TypeCaps = T(Iso, Mut, Imm);
inline const auto Literal =
T(String, Escaped, Char, Hex, Oct, Bin, Int, Float, HexFloat, LLVM);
inline const auto TypeElem = TypeCaps /
T(Type,
FQType,
Trait,
TypeTuple,
Self,
TypeList,
TypeView,
TypeIsect,
TypeUnion,
TypeVar,
Package,
TypeSubtype,
TypeTrue,
TypeFalse);
inline const auto Object0 = Literal /
T(RefVar,
RefVarLHS,
RefLet,
Unit,
Tuple,
Lambda,
Call,
NLRCheck,
Assign,
Expr,
ExprSeq,
DontCare,
Conditional,
TypeTest,
Cast);
inline const auto Object = Object0 / (T(TypeAssert) << (Object0 * T(Type)));
inline const auto Operator = T(FQFunction) / T(Selector);
inline const auto Operator = T(FQFunction, Selector);
inline const auto RhsCall = T(Call)
<< ((T(Selector) << T(Rhs)) /
(T(FQFunction) << (T(FQType) * (T(Selector) << T(Rhs)))));
// Helper functions for generating AST fragments.
Node err(Node node, const std::string& msg);
Node typevar(Location loc);
Node typevar(Node& node);
Node typevar(Match& _);
Node typevar(Match& _, const Token& t);
Node inherit();
@ -184,13 +216,18 @@ namespace verona
Node nonlocal(Match& _);
Node unittype();
Node unit();
Node booltype();
Node booltrue();
Node boolfalse();
Node cell();
Node reftype(Node t);
Node tuple_to_args(Node n);
Node selector(Node name, Node ta = TypeArgs);
Node selector(Location name, Node ta = TypeArgs);
bool is_llvm_call(Node op);
Node call(Node op, Node lhs = {}, Node rhs = {}, bool post_nlr = false);
Node call(Node op, Node lhs = {}, Node rhs = {});
Node call_lhs(Node call);
Node load(Node arg, bool post_nlr = false);
Node load(Node arg);
bool is_implicit(Node n);
bool conflict(Node& a, Node& b);
@ -198,7 +235,8 @@ namespace verona
Parse parser();
PassDef modules();
PassDef structure();
PassDef memberconflict();
PassDef conditionals();
PassDef reference();
PassDef typenames();
PassDef typeview();
PassDef typefunc();
@ -206,8 +244,9 @@ namespace verona
PassDef typeflat();
PassDef typevalid();
PassDef codereuse();
PassDef conditionals();
PassDef reference();
PassDef memberconflict();
PassDef resetimplicit();
PassDef typereference();
PassDef reverseapp();
PassDef application();
PassDef assignlhs();
@ -226,6 +265,7 @@ namespace verona
PassDef drop();
PassDef namearity();
PassDef validtypeargs();
PassDef typeinfer();
struct Options : public trieste::Options
{

Просмотреть файл

@ -9,9 +9,39 @@
namespace verona
{
size_t Lookup::sub(Node& node)
{
// Substitutes inside of `node`, but not `node` itself.
size_t changes = 0;
for (auto child : *node)
{
while ((child == FQType) && ((child / Type) == TypeParamName))
{
auto l = resolve_fq(child);
auto it = bindings.find(l.def);
if (it == bindings.end())
break;
auto bind = clone(it->second);
if (bind == Type)
bind = bind / Type;
node->replace(child, bind);
child = bind;
}
changes += sub(child);
}
return changes;
}
static void apply_typeargs(Lookup& lookup, Node ta)
{
if (!lookup.def->type().in({Class, TypeAlias, Function}))
if (!lookup.def->in({Class, TypeAlias, Function}))
return;
auto tp = lookup.def / TypeParams;
@ -39,23 +69,29 @@ namespace verona
tp->begin() + n,
tp->end(),
std::inserter(lookup.bindings, lookup.bindings.end()),
[](auto param) {
return std::make_pair(
param, Type << (TypeVar ^ param->fresh(l_typevar)));
});
[](auto param) { return std::make_pair(param, typevar(param)); });
}
Lookups lookup(Node id, Node ta)
{
assert(id->type().in({Ident, Symbol}));
assert(!ta || (ta->type() == TypeArgs));
assert(id->in({Ident, Symbol, Self}));
assert(!ta || (ta == TypeArgs));
Lookups result;
if (id == Self)
{
auto def = id->parent({Class, Trait});
Lookup l(def);
apply_typeargs(l, ta);
result.emplace(l);
return result;
}
auto defs = id->lookup();
Lookups result;
for (auto& def : defs)
{
if (def->type() == Use)
if (def == Use)
{
// Expand Use nodes by looking down into the target type.
if (def->precedes(id))
@ -89,7 +125,7 @@ namespace verona
if (!inserted.second)
return {};
if (lookup.def->type().in({Class, Trait, Function}))
if (lookup.def->in({Class, Trait, Function}))
{
// Return all lookdowns in the found class, trait, or function.
Lookups result;
@ -107,45 +143,43 @@ namespace verona
return result;
}
else if (lookup.def->type() == TypeAlias)
else if (lookup.def == TypeAlias)
{
// Replace the def with our type alias and try again.
lookup.def = lookup.def / Type;
}
else if (lookup.def->type() == TypeParam)
else if (lookup.def == TypeParam)
{
// Replace the typeparam with the bound typearg and try again.
auto it = lookup.bindings.find(lookup.def);
// Except in testing, there should always be a binding. If it's bound
// to itself, then we're done.
if (
(it == lookup.bindings.end()) ||
(it->second->type() == TypeParamBind))
if ((it == lookup.bindings.end()) || (it->second == TypeParamBind))
return {};
lookup.def = it->second;
}
// The remainder of cases arise from a Use, a TypeAlias, or a TypeParam.
// They will all result in some number of name resolutions.
else if (lookup.def->type() == Type)
else if (lookup.def == Type)
{
// Replace the def with the content of the type and try again.
// Use `front()` instead of `def / Type` to allow looking up in `use`
// directives before Type is no longer a sequence.
lookup.def = lookup.def->front();
}
else if (lookup.def->type().in({FQType, FQFunction}))
else if (lookup.def->in({FQType, FQFunction}))
{
// Resolve the name and try again.
lookup = resolve_fq(lookup.def);
}
else if (lookup.def->type() == TypeView)
else if (lookup.def == TypeView)
{
// Replace the def with the rhs of the view and try again.
lookup.def = lookup.def->back();
}
else if (lookup.def->type() == TypeIsect)
else if (lookup.def == TypeIsect)
{
// Return everything we find.
Lookups result;
@ -159,12 +193,12 @@ namespace verona
return result;
}
else if (lookup.def->type() == TypeUnion)
else if (lookup.def == TypeUnion)
{
// TODO: return only things that are identical in all disjunctions
return {};
}
else if (lookup.def->type().in({TypeList, TypeTuple, TypeVar}))
else if (lookup.def->in({TypeList, TypeTuple, TypeVar}))
{
// Nothing to do here.
return {};
@ -180,7 +214,7 @@ namespace verona
bool lookup_type(Node id, std::initializer_list<Token> t)
{
auto defs = lookup(id, {});
return (defs.size() == 1) && defs.begin()->def->type().in(t);
return (defs.size() == 1) && defs.begin()->def->in(t);
}
bool lookup_type(const NodeRange& n, std::initializer_list<Token> t)
@ -190,13 +224,12 @@ namespace verona
static bool resolve_selector(Lookup& p, Node n)
{
assert(n->type() == Selector);
assert(n == Selector);
if (!p.def)
return false;
auto hand = (n / Ref)->type();
auto id = n / Ident;
auto defs = p.def->lookdown(id->location());
@ -207,7 +240,7 @@ namespace verona
for (auto& def : defs)
{
if (
(def->type() == Function) && ((def / Ref)->type() == hand) &&
(def == Function) && ((def / Ref) == hand) &&
((def / Params)->size() == arity))
{
p = p.make(def);
@ -221,21 +254,21 @@ namespace verona
static bool resolve_typename(Lookup& p, Node n)
{
assert(n->type().in(
{TypeClassName, TypeAliasName, TypeParamName, TypeTraitName}));
assert(n->in({TypeClassName, TypeAliasName, TypeParamName, TypeTraitName}));
auto def = p.def;
if (!p.def)
if (!def)
return false;
auto id = n / Ident;
auto defs = p.def->lookdown(id->location());
auto defs = def->lookdown(id->location());
if (defs.size() != 1)
return false;
p = p.make(*defs.begin());
if (n->type().in({TypeClassName, TypeAliasName}))
if (n->in({TypeClassName, TypeAliasName}))
apply_typeargs(p, n / TypeArgs);
return true;
@ -243,18 +276,18 @@ namespace verona
static Lookup resolve_fqtype(Node fq)
{
assert(fq->type() == FQType);
assert(fq == FQType);
Lookup p(fq->parent(Top));
auto path = fq / TypePath;
for (auto& n : *path)
{
if (n->type() == Selector)
if (n == Selector)
{
if (!resolve_selector(p, n))
return {};
}
else if (n->type().in(
else if (n->in(
{TypeClassName, TypeAliasName, TypeParamName, TypeTraitName}))
{
if (!resolve_typename(p, n))
@ -270,10 +303,10 @@ namespace verona
Lookup resolve_fq(Node fq)
{
if (fq->type() == FQType)
if (fq == FQType)
return resolve_fqtype(fq);
assert(fq->type() == FQFunction);
assert(fq == FQFunction);
auto p = resolve_fqtype(fq / FQType);
if (!resolve_selector(p, fq / Selector))
@ -294,7 +327,7 @@ namespace verona
if (it != lookup.bindings.end())
ta << clone(it->second);
else if (fresh)
ta << (Type << (TypeVar ^ node->fresh(l_typevar)));
ta << typevar(node);
else
ta << TypeParamBind;
}
@ -304,7 +337,7 @@ namespace verona
static Node make_fq(Lookup& lookup, bool fresh)
{
if (!lookup.def->type().in({Class, TypeAlias, TypeParam, Trait, Function}))
if (!lookup.def->in({Class, TypeAlias, TypeParam, Trait, Function}))
return lookup.def;
Node path = TypePath;
@ -312,27 +345,27 @@ namespace verona
while (node)
{
if (node->type() == Class)
if (node == Class)
{
path
<< (TypeClassName << clone(node / Ident)
<< make_typeargs(node, lookup, fresh));
}
else if (node->type() == TypeAlias)
else if (node == TypeAlias)
{
path
<< (TypeAliasName << clone(node / Ident)
<< make_typeargs(node, lookup, fresh));
}
else if (node->type() == TypeParam)
else if (node == TypeParam)
{
path << (TypeParamName << clone(node / Ident));
}
else if (node->type() == Trait)
else if (node == Trait)
{
path << (TypeTraitName << clone(node / Ident));
}
else if (node->type() == Function)
else if (node == Function)
{
auto arity = std::to_string((node / Params)->size());
@ -347,8 +380,7 @@ namespace verona
std::reverse(path->begin(), path->end());
node = path->pop_back();
if (node->type().in(
{TypeClassName, TypeAliasName, TypeParamName, TypeTraitName}))
if (node->in({TypeClassName, TypeAliasName, TypeParamName, TypeTraitName}))
return FQType << path << node;
assert(!path->empty());
@ -364,7 +396,7 @@ namespace verona
Node local_fq(Node node)
{
// Build an FQType for the local type.
if (!node->type().in({Class, TypeAlias, TypeParam, Trait, Function}))
if (!node->in({Class, TypeAlias, TypeParam, Trait, Function}))
node = node->parent({Class, TypeAlias, TypeParam, Trait, Function});
Lookup l(node);
@ -373,14 +405,26 @@ namespace verona
Node append_fq(Node fq, Node node)
{
assert(fq->type() == FQType);
assert(fq->type().in({FQType, FQFunction}));
assert(node->in(
{TypeClassName, TypeAliasName, TypeParamName, TypeTraitName, Selector}));
if (node->type() == Selector)
if (fq == FQFunction)
{
// FQFunction + Selector = not allowed
assert(node != Selector);
// FQFunction + Type = FQType
return FQType << (clone(fq / FQType / TypePath)
<< clone(fq / FQType / Type) << clone(fq / Selector))
<< node;
}
// FQType + Selector = FQFunction
if (node == Selector)
return FQFunction << clone(fq) << node;
assert(node->type().in(
{TypeClassName, TypeAliasName, TypeParamName, TypeTraitName}));
// FQType + Type = FQType
return FQType << (clone(fq / TypePath) << clone(fq / Type)) << node;
}
}

Просмотреть файл

@ -27,6 +27,8 @@ namespace verona
{
return (def < other.def) && (bindings < other.bindings);
}
size_t sub(Node& node);
};
using Lookups = std::set<Lookup>;

Просмотреть файл

@ -173,24 +173,28 @@ namespace verona
},
// Bool.
"(?:true|false)\\b" >> [](auto& m) { m.add(Bool); },
"true\\b" >> [](auto& m) { m.add(True); },
"false\\b" >> [](auto& m) { m.add(False); },
// Hex float.
"0x[[:xdigit:]]+\\.[[:xdigit:]]+(?:p[+-][[:digit:]]+)?\\b" >>
"0x[_[:xdigit:]]+\\.[_[:xdigit:]]+(?:p[+-][_[:digit:]]+)?\\b" >>
[](auto& m) { m.add(HexFloat); },
// Hex.
"0x[_[:xdigit:]]+\\b" >> [](auto& m) { m.add(Hex); },
// Float.
"[[:digit:]][_[:digit:]]*\\.[_[:digit:]]+(?:e[+-]?[_[:digit:]]+)?\\b" >>
[](auto& m) { m.add(Float); },
// Bin.
"0b[_01]+\\b" >> [](auto& m) { m.add(Bin); },
// Float.
"[[:digit:]]+\\.[[:digit:]]+(?:e[+-]?[[:digit:]]+)?\\b" >>
[](auto& m) { m.add(Float); },
// Oct.
"0o[_01234567]+\\b" >> [](auto& m) { m.add(Oct); },
// Hex.
"0x[_[:xdigit:]]+\\b" >> [](auto& m) { m.add(Hex); },
// Int.
"[[:digit:]]+\\b" >> [](auto& m) { m.add(Int); },
"[[:digit:]][_[:digit:]]*\\b" >> [](auto& m) { m.add(Int); },
// Escaped string.
"\"((?:\\\"|[^\"])*?)\"" >> [](auto& m) { m.add(Escaped, 1); },
@ -334,7 +338,6 @@ namespace verona
});
p.gen({
Bool >> [](auto& rnd) { return rnd() % 2 ? "true" : "false"; },
Int >> [](auto& rnd) { return std::to_string(rnd()); },
Hex >> [](auto& rnd) { return fmt::format("{:#x}", rnd()); },
Bin >> [](auto& rnd) { return fmt::format("{:#b}", rnd()); },

Просмотреть файл

@ -4,8 +4,8 @@
namespace verona
{
inline const auto Liftable = T(Tuple) / T(Call) / T(Conditional) /
T(FieldRef) / T(TypeTest) / T(Cast) / T(Selector) / Literal;
inline const auto Liftable =
Literal / T(Tuple, Call, Conditional, FieldRef, TypeTest, Cast, Selector);
PassDef anf()
{
@ -22,7 +22,7 @@ namespace verona
},
// Lift RefLet and Return.
T(Expr) << (T(RefLet) / T(Return))[Op] >> [](Match& _) { return _(Op); },
T(Expr) << T(RefLet, Return)[Op] >> [](Match& _) { return _(Op); },
// Lift LLVM literals that are at the block level.
In(Block) * (T(Expr) << T(LLVM)[LLVM]) >>

Просмотреть файл

@ -1,6 +1,7 @@
// Copyright Microsoft and Project Verona Contributors.
// SPDX-License-Identifier: MIT
#include "../lang.h"
#include "../lookup.h"
namespace verona
{
@ -13,16 +14,13 @@ namespace verona
T(Ref) * T(RefVar)[RefVar] >>
[](Match& _) { return RefVarLHS << *_[RefVar]; },
T(Ref) * (T(NLRCheck) << (IsImplicit[Implicit] * RhsCall[Call])) >>
[](Match& _) { return NLRCheck << _(Implicit) << call_lhs(_(Call)); },
T(Ref) * (T(NLRCheck) << RhsCall[Call]) >>
[](Match& _) { return NLRCheck << call_lhs(_(Call)); },
// Try expressions.
T(Try) * (T(NLRCheck) << (IsImplicit * T(Call)[Call])) >>
T(Try) * (T(NLRCheck) << T(Call)[Call]) >>
[](Match& _) { return _(Call); },
T(Try) * T(Lambda)[Lambda] >>
[](Match& _) { return call(selector(l_apply), _(Lambda)); },
// Adjacency: application.
In(Expr) * Object[Lhs] * Object[Rhs] >>
[](Match& _) { return call(selector(l_apply), _(Lhs), _(Rhs)); },
@ -44,7 +42,7 @@ namespace verona
[](Match& _) { return TupleFlatten << (Expr << _(Lhs)); },
// Use `_` (DontCare) for partial application of arbitrary arguments.
T(Call)
T(Call)[Call]
<< (Operator[Op] *
(T(Args)
<< ((T(Expr) << !T(DontCare))++ *
@ -53,23 +51,34 @@ namespace verona
(T(TypeAssert) << (T(DontCare) * T(Type))))) *
T(Expr)++))[Args]) >>
[](Match& _) {
Node params = Params;
// Create the anonymous type name.
bool in_nlrcheck = _(Call)->parent() == NLRCheck;
auto class_id = _.fresh(l_lambda);
// Build an FQType for the anonymous type.
auto fq = append_fq(
local_fq(_(Call)->parent(Function)),
TypeClassName << (Ident ^ class_id) << TypeArgs);
// Start with a Self parameter.
Node params = Params
<< (Param << (Ident ^ _.fresh(l_self)) << (Type << Self));
Node args = Tuple;
for (auto& arg : *_(Args))
{
auto expr = arg->front();
if (expr->type() == DontCare)
if (expr == DontCare)
{
auto id = _.fresh(l_param);
params << (Param << (Ident ^ id) << typevar(_) << DontCare);
params << (Param << (Ident ^ id) << typevar(_));
args << (Expr << (RefLet << (Ident ^ id)));
}
else if (expr->type() == TypeAssert)
else if (expr == TypeAssert)
{
auto id = _.fresh(l_param);
params << (Param << (Ident ^ id) << (expr / Type) << DontCare);
params << (Param << (Ident ^ id) << (expr / Type));
args << (Expr << (RefLet << (Ident ^ id)));
}
else
@ -78,23 +87,42 @@ namespace verona
}
}
return Lambda << TypeParams << params << typevar(_) << typepred()
<< (Block << (Expr << call(_(Op), args)));
// Add the create and apply functions to the anonymous type.
auto create_func = Function
<< Implicit << Rhs << (Ident ^ l_create) << TypeParams << Params
<< typevar(_) << DontCare << typepred()
<< (Block << (Expr << call(append_fq(fq, selector(l_new)))));
auto apply_func = Function << LambdaFunc << Rhs << (Ident ^ l_apply)
<< TypeParams << params << typevar(_)
<< DontCare << typepred()
<< (Block << (Expr << call(_(Op), args)));
auto classdef = Class << (Ident ^ class_id) << TypeParams
<< (Inherit << DontCare) << typepred()
<< (ClassBody << create_func << apply_func);
auto create = call(append_fq(fq, selector(l_create)));
if (in_nlrcheck)
create = create / Call;
return Seq << (Lift << Block << classdef) << create;
},
// Remove the NLRCheck from a partial application.
T(NLRCheck) << (IsImplicit * T(Lambda)[Lambda] * End) >>
[](Match& _) { return _(Lambda); },
// Remaining DontCare are discarded bindings.
In(Expr) * T(DontCare) >>
[](Match& _) {
// Remaining DontCare are discarded bindings.
return Let << (Ident ^ _.fresh());
},
[](Match& _) { return Let << (Ident ^ _.fresh()); },
// Turn remaining uses of Unit into std::builtin::Unit::create()
// Turn Unit into std::builtin::Unit::create()
T(Unit) >> [](Match&) { return unit(); },
// Turn True into std::builtin::Bool::make_true()
T(True) >> [](Match&) { return booltrue(); },
// Turn False into std::builtin::Bool::make_false()
T(False) >> [](Match&) { return boolfalse(); },
T(Ellipsis) >>
[](Match& _) {
return err(_(Ellipsis), "`...` must be after a value in a tuple");
@ -103,6 +131,7 @@ namespace verona
// Compact expressions.
In(Expr) * T(Expr) << (Any[Expr] * End) >>
[](Match& _) { return _(Expr); },
T(Expr) << (T(Expr)[Expr] * End) >> [](Match& _) { return _(Expr); },
};
}

Просмотреть файл

@ -31,21 +31,16 @@ namespace verona
return Expr << (TypeAssert << call_lhs(_(Call)) << _(Type));
},
on_lhs(
T(Expr) << (T(NLRCheck) << (IsImplicit[Implicit] * RhsCall[Call]))) >>
[](Match& _) {
return Expr << (NLRCheck << _(Implicit) << call_lhs(_(Call)));
},
on_lhs(T(Expr) << (T(NLRCheck) << RhsCall[Call])) >>
[](Match& _) { return Expr << (NLRCheck << call_lhs(_(Call))); },
on_lhs(
T(Expr)
<< (T(TypeAssert)
<< ((T(NLRCheck) << (IsImplicit[Implicit] * RhsCall[Call])) *
T(Type)[Type]))) >>
<< ((T(NLRCheck) << RhsCall[Call]) * T(Type)[Type]))) >>
[](Match& _) {
return Expr
<< (TypeAssert << (NLRCheck << _(Implicit) << call_lhs(_(Call)))
<< _(Type));
<< (TypeAssert << (NLRCheck << call_lhs(_(Call))) << _(Type));
},
// Turn a RefVar on the LHS of an assignment into a RefVarLHS.

Просмотреть файл

@ -14,7 +14,7 @@ namespace verona
(T(Expr)
<< ((T(Let) << T(Ident)[Ident]) /
(T(TypeAssert)
<< (T(Let) << T(Ident)[Ident]) * T(Type)[Type]))) *
<< (T(Expr) << (T(Let) << T(Ident)[Ident])) * T(Type)[Type]))) *
T(Expr)[Rhs] * End >>
[](Match& _) {
return Expr << (Bind << _(Ident) << typevar(_, Type) << _(Rhs));
@ -43,7 +43,7 @@ namespace verona
{
auto lhs_e = lhs_child->front();
if (lhs_e->type() == Let)
if (lhs_e == Let)
{
// lhs_child is already a Let.
lhs_tuple << (Expr << (RefLet << clone(lhs_e / Ident)));
@ -71,7 +71,7 @@ namespace verona
// TypeAssert comes after the let bindings for the LHS.
if (ty)
seq << (Expr << (TypeAssert << lhs_tuple << ty));
seq << (Expr << (TypeAssert << (Expr << lhs_tuple) << ty));
// The RHS tuple is the last expression in the sequence.
return Expr << (seq << rhs_e << (Expr << rhs_tuple));

Просмотреть файл

@ -8,7 +8,7 @@ namespace verona
PassDef autocreate()
{
return {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
In(Class) * T(ClassBody)[ClassBody] >> ([](Match& _) -> Node {
auto class_body = _(ClassBody);
@ -17,51 +17,42 @@ namespace verona
for (auto& node : *class_body)
{
if (node->type().in({FieldLet, FieldVar}))
{
auto id = node / Ident;
auto ty = node / Type;
auto def_arg = node / Default;
if (!node->in({FieldLet, FieldVar}))
continue;
// Add each field in order to the call to `new` and the create
// function parameters.
new_args << (Expr << (RefLet << clone(id)));
new_params
<< ((Param ^ def_arg) << clone(id) << clone(ty) << def_arg);
}
auto id = node / Ident;
auto ty = node / Type;
auto def_arg = node / Default;
// Add each field in order to the call to `new` and the create
// function parameters.
new_args << (Expr << (RefLet << clone(id)));
new_params
<< ((Param ^ def_arg)
<< clone(id) << clone(ty) << clone(def_arg));
}
// Create the `new` function, with default arguments set to the field
// initializers. Mark `new` as explicit, so that errors when type
// checking `new` are reported.
auto body = ClassBody
<< *_[ClassBody]
class_body
<< (Function << Explicit << Rhs << (Ident ^ l_new) << TypeParams
<< new_params << typevar(_) << DontCare << typepred()
<< (Block << (Expr << unit())));
<< (Block << (Expr << Unit)));
// If we already have a create function, don't emit one.
if (class_body->parent()->lookdown(l_create).empty())
{
// Create the `create` function.
auto fq_new = append_fq(local_fq(_(ClassBody)), selector(l_new));
body
class_body
<< (Function << Implicit << Rhs << (Ident ^ l_create)
<< TypeParams << clone(new_params) << typevar(_)
<< DontCare << typepred()
<< (Block << (Expr << call(fq_new, new_args))));
<< (Block
<< (Expr << New << tuple_to_args(new_args))));
}
return body;
return NoChange;
}),
// Strip the default field values.
T(FieldLet) << (T(Ident)[Ident] * T(Type)[Type] * Any) >>
[](Match& _) { return FieldLet << _(Ident) << _(Type); },
T(FieldVar) << (T(Ident)[Ident] * T(Type)[Type] * Any) >>
[](Match& _) { return FieldVar << _(Ident) << _(Type); },
}};
}
}

Просмотреть файл

@ -7,9 +7,9 @@ namespace verona
PassDef autofields()
{
return {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
(T(FieldVar) / T(FieldLet))[Op] << (T(Ident)[Ident] * T(Type)[Type]) >>
T(FieldVar, FieldLet)[Op] << (T(Ident)[Ident] * T(Type)[Type]) >>
([](Match& _) -> Node {
// If it's a FieldLet, generate only an RHS function. If it's a
// FieldVar, generate an LHS function, which will autogenerate an
@ -17,18 +17,17 @@ namespace verona
auto field = _(Op);
auto id = _(Ident);
auto self_id = _.fresh(l_self);
Token hand = (field->type() == FieldVar) ? Lhs : Rhs;
Token hand = (field == FieldVar) ? Lhs : Rhs;
auto expr = FieldRef << (RefLet << (Ident ^ self_id)) << clone(id);
if (hand == Rhs)
expr = load(expr);
auto f = Function << Implicit << hand << clone(id) << TypeParams
<< (Params
<< (Param << (Ident ^ self_id)
<< (Type << Self) << DontCare))
<< clone(_(Type)) << DontCare << typepred()
<< (Block << (Expr << expr));
auto f = Function
<< Implicit << hand << clone(id) << TypeParams
<< (Params << (Param << (Ident ^ self_id) << (Type << Self)))
<< clone(_(Type)) << DontCare << typepred()
<< (Block << (Expr << expr));
return Seq << field << f;
}),

Просмотреть файл

@ -8,13 +8,12 @@ namespace verona
PassDef autorhs()
{
return {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
T(Function)[Function]
<< (IsImplicit * T(Lhs) * T(Ident)[Ident] *
T(TypeParams)[TypeParams] * T(Params)[Params] * T(Type)[Type] *
T(DontCare) * T(TypePred)[TypePred] *
(T(Block) / T(DontCare))) >>
T(DontCare) * T(TypePred)[TypePred] * T(Block, DontCare)) >>
([](Match& _) -> Node {
auto f = _(Function);
auto id = _(Ident);
@ -28,8 +27,7 @@ namespace verona
for (auto def : defs)
{
if (
(def != f) && (def->type() == Function) &&
((def / Ref)->type() != Rhs) &&
(def != f) && (def == Function) && ((def / Ref) != Rhs) &&
((def / Ident)->location() == id->location()) &&
((def / Params)->size() == params->size()))
{

Просмотреть файл

@ -12,44 +12,13 @@ namespace verona
Nodes deps;
};
size_t type_substitution(NodeMap<Node>& bindings, Node& node)
{
// Substitutes inside of `node`, but not `node` itself.
size_t changes = 0;
for (auto child : *node)
{
while ((child->type() == FQType) &&
((child / Type)->type() == TypeParamName))
{
auto l = resolve_fq(child);
auto it = bindings.find(l.def);
if (it == bindings.end())
break;
auto bind = clone(it->second);
if (bind->type() == Type)
bind = bind / Type;
node->replace(child, bind);
child = bind;
}
changes += type_substitution(bindings, child);
}
return changes;
}
PassDef codereuse()
{
auto pending = std::make_shared<NodeMap<Pending>>();
auto ready = std::make_shared<Nodes>();
PassDef codereuse = {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
T(Class)[Class]
<< (T(Ident)[Ident] * T(TypeParams) *
@ -70,29 +39,29 @@ namespace verona
if (!l.def)
continue;
if (l.def->type() == FQType)
if (l.def == FQType)
{
auto ll = resolve_fq(l.def);
ll.bindings.merge(l.bindings);
worklist.push_back(ll);
}
else if (l.def->type().in({Type, TypeIsect}))
else if (l.def->in({Type, TypeIsect}))
{
for (auto& t : *l.def)
worklist.emplace_back(l.make(t));
}
else if (l.def->type() == TypeAlias)
else if (l.def == TypeAlias)
{
// Carry typeargs forward.
worklist.emplace_back(l.make(l.def / Type));
}
else if (l.def->type() == Trait)
else if (l.def == Trait)
{
pend.inherit.push_back(l);
}
else if (l.def->type() == Class)
else if (l.def == Class)
{
if ((l.def / Inherit / Inherit)->type() == Type)
if ((l.def / Inherit / Inherit) == Type)
{
// Keep track of the inheritance graph.
(*pending)[l.def].deps.push_back(cls);
@ -126,16 +95,16 @@ namespace verona
{
for (auto f : *(from.def / ClassBody))
{
if (!f->type().in({FieldLet, FieldVar, Function}))
if (!f->in({FieldLet, FieldVar, Function}))
continue;
// Don't inherit functions without implementations.
if ((f->type() == Function) && ((f / Block)->type() == DontCare))
if ((f == Function) && ((f / Block) == DontCare))
continue;
// If we have an explicit version that conflicts, don't inherit.
auto defs = cls->lookdown((f / Ident)->location());
if (std::any_of(defs.begin(), defs.end(), [&](Node& def) -> bool {
if (std::any_of(defs.begin(), defs.end(), [&](Node& def) {
return conflict(f, def);
}))
continue;
@ -147,7 +116,7 @@ namespace verona
changes++;
// Type substitution in the inherited member.
changes += type_substitution(from.bindings, f);
changes += from.sub(f);
}
}

Просмотреть файл

@ -104,22 +104,6 @@ namespace verona
_(Else),
"`else` must follow an `if` and be followed by an `if` or braces");
},
// Strip implicit/explicit marker from fields.
(T(FieldLet) / T(FieldVar))[FieldLet]
<< (IsImplicit * T(Ident)[Ident] * T(Type)[Type] * Any[Default]) >>
[](Match& _) {
Node field = _(FieldLet)->type();
return field << _(Ident) << _(Type) << _(Default);
},
// Reset functions marked as implicit to be explicit.
T(Function)[Function] << T(Implicit) >>
[](Match& _) {
auto f = _(Function);
(f / Implicit) = Explicit;
return f;
},
};
}
}

Просмотреть файл

@ -8,81 +8,96 @@ namespace verona
PassDef defaultargs()
{
return {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
T(Function)[Function]
<< (T(Explicit) * Hand[Ref] * T(Ident)[Ident] *
T(TypeParams)[TypeParams] *
(T(Params)
<< ((T(Param) << (T(Ident) * T(Type) * T(DontCare)))++[Lhs] *
(T(Param) << (T(Ident) * T(Type) * T(NLRCheck)))++[Rhs] *
End)) *
T(Type)[Type] * T(DontCare) * T(TypePred)[TypePred] *
(T(Block) / T(DontCare))[Block]) >>
T(Function)
<< (IsImplicit[Implicit] * Hand[Ref] * T(Ident)[Ident] *
T(TypeParams)[TypeParams] * T(Params)[Params] * T(Type)[Type] *
T(LLVMFuncType, DontCare)[LLVMFuncType] *
T(TypePred)[TypePred] * T(Block, DontCare)[Block]) >>
[](Match& _) {
Node seq = Seq;
auto hand = _(Ref);
auto implicit = _(Implicit)->type();
auto hand = _(Ref)->type();
auto id = _(Ident);
auto tp = _(TypeParams);
auto params = _(Params);
auto ty = _(Type);
auto llvmty = _(LLVMFuncType);
auto pred = _(TypePred);
auto lhs = _[Lhs];
auto rhs = _[Rhs];
auto fq = local_fq(_(Function));
Node params = Params;
Node new_params = Params;
Node args = Tuple;
bool has_default = false;
// Start with parameters that have no default value.
for (auto it = lhs.first; it != lhs.second; ++it)
for (auto& param : *params)
{
auto param_id = *it / Ident;
params << (Param << clone(param_id) << clone(*it / Type));
auto param_id = param / Ident;
auto param_type = param / Type;
auto block = param / Default;
args << (Expr << (RefLet << clone(param_id)));
}
for (auto it = rhs.first; it != rhs.second; ++it)
{
// At this point, the default argument is a create call on the
// anonymous class derived from the lambda. Apply the created
// lambda to get the default argument.
auto def_arg = call(selector(l_apply), (*it / Default));
if (block == DontCare)
{
if (has_default)
{
params->replace(
param,
err(
param,
"Can't put a parameter with no default value after a "
"parameter with one"));
}
}
else
{
has_default = true;
auto def_arg = block->back();
// Add the default argument to the forwarding call.
args << (Expr << def_arg);
// Syntactically, the last statement in the block is the default
// argument expression. WF doesn't enforce this.
if (def_arg == Expr)
block->pop_back();
else
def_arg = Expr << Unit;
// Add a new function that calls the arity+1 function. Mark it as
// explicit, so that errors when type checking the default
// arguments are reported.
seq
<< (Function
<< Explicit << clone(hand) << clone(id) << clone(tp)
<< clone(params) << clone(ty) << DontCare << clone(pred)
<< (Block << (Expr << (call(clone(fq), clone(args))))));
// Evaluate the default argument and call the arity+1 function.
block << (Expr
<< (Assign << (Expr << (Let << (Ident ^ param_id)))
<< def_arg))
<< (Expr << Self << DoubleColon << selector(id)
<< tuple_to_args(clone(args)));
// Add a parameter.
auto param_id = *it / Ident;
params << (Param << clone(param_id) << clone(*it / Type));
// Add a new function that calls the arity+1 function. Mark it
// as explicit, so that errors when type checking the default
// arguments are reported.
seq
<< (Function << implicit << hand << clone(id) << clone(tp)
<< clone(new_params) << clone(ty)
<< clone(llvmty) << clone(pred) << block);
}
// Replace the last argument with a reference to the parameter.
args->pop_back();
args << (Expr << (RefLet << clone(param_id)));
// Add the parameter to the new parameter list.
new_params << (Param << clone(param_id) << clone(param_type));
}
// The original function, with no default arguments.
return seq
<< (Function << Explicit << hand << id << tp << params << ty
<< DontCare << pred << _(Block));
<< (Function << implicit << hand << id << tp << new_params << ty
<< llvmty << pred << _(Block));
},
T(Param) << (T(Ident)[Ident] * T(Type)[Type] * T(DontCare)) >>
[](Match& _) { return Param << _(Ident) << _(Type); },
T(Param)[Param] << (T(Ident) * T(Type) * T(NLRCheck)) >>
// Strip the default field values.
T(FieldLet)
<< (IsImplicit[Implicit] * T(Ident)[Ident] * T(Type)[Type] * Any) >>
[](Match& _) {
return err(
_(Param),
"Can't put a default value before a non-defaulted value");
return FieldLet << _(Implicit) << _(Ident) << _(Type);
},
T(FieldVar)
<< (IsImplicit[Implicit] * T(Ident)[Ident] * T(Type)[Type] * Any) >>
[](Match& _) {
return FieldVar << _(Implicit) << _(Ident) << _(Type);
},
}};
}

Просмотреть файл

@ -8,7 +8,7 @@ namespace verona
PassDef defbeforeuse()
{
return {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
T(RefLet) << T(Ident)[Ident] >> ([](Match& _) -> Node {
if (!is_implicit(_(Ident)) && !lookup_type(_(Ident), {Bind, Param}))

Просмотреть файл

@ -51,13 +51,13 @@ namespace verona
return true;
// Only check parents and successors if this isn't an early return.
return (block->back()->type() != Return) &&
return (block->back() != Return) &&
(is_parent(of, block) || is_successor_or_child(of, block));
}
bool is_parent(Node of, Node block)
{
if (of->parent()->type() == Function)
if (of->parent() == Function)
return false;
auto& parent = parents.at(of);
@ -129,7 +129,7 @@ namespace verona
{
auto ref = it->second;
auto parent = ref->parent();
bool immediate = parent->type() == Block;
bool immediate = parent == Block;
if (immediate && (parent->back() != ref))
parent->replace(ref);
@ -151,7 +151,7 @@ namespace verona
auto ref = it->second;
auto id = ref / Ident;
auto parent = ref->parent()->shared_from_this();
bool immediate = parent->type() == Block;
bool immediate = parent == Block;
bool discharging = true;
// We're the last use if there is no following use in this or any
@ -223,16 +223,10 @@ namespace verona
auto drop_map = std::make_shared<std::vector<track>>();
PassDef drop = {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
(T(Param) / T(Bind)) << T(Ident)[Ident] >>
([drop_map](Match& _) -> Node {
drop_map->back().gen(_(Ident)->location());
return NoChange;
}),
T(RefLet)[RefLet] << T(Ident)[Ident] >> ([drop_map](Match& _) -> Node {
drop_map->back().ref(_(Ident)->location(), _(RefLet));
T(Param, Bind) << T(Ident)[Ident] >> ([drop_map](Match& _) -> Node {
drop_map->back().gen(_(Ident)->location());
return NoChange;
}),
@ -250,19 +244,26 @@ namespace verona
}),
}};
drop.pre(Function, [drop_map](Node f) {
auto llvm = (f / LLVMFuncType) == LLVMFuncType;
drop_map->push_back(track(llvm));
return 0;
});
drop.pre(Block, [drop_map](Node node) {
drop_map->back().pre_block(node);
return 0;
});
drop.post(Block, [drop_map](Node) {
drop_map->back().post_block();
drop.post(RefLet, [drop_map](Node node) {
// RefLet is handled with a post-order step to avoid an immediate RefLet
// that precedes a nested RefLet being handled after the nested RefLet.
drop_map->back().ref((node / Ident)->location(), node);
return 0;
});
drop.pre(Function, [drop_map](Node f) {
auto llvm = (f / LLVMFuncType)->type() == LLVMFuncType;
drop_map->push_back(track(llvm));
drop.post(Block, [drop_map](Node) {
drop_map->back().post_block();
return 0;
});

Просмотреть файл

@ -10,118 +10,100 @@ namespace verona
auto freevars = std::make_shared<std::vector<std::set<Location>>>();
PassDef lambda =
{dir::bottomup,
{
T(RefLet) << T(Ident)[Ident] >> ([freevars](Match& _) -> Node {
if (!freevars->empty())
{
// If we don't have a definition within the scope of the lambda,
// then it's a free variable.
auto id = _(Ident);
{
dir::bottomup | dir::once,
{
T(RefLet) << T(Ident)[Ident] >> ([freevars](Match& _) -> Node {
if (!freevars->empty())
{
// If we don't have a definition within the scope of the lambda,
// then it's a free variable.
auto id = _(Ident);
if (id->lookup(id->parent(Lambda)).empty())
freevars->back().insert(id->location());
}
if (id->lookup(id->parent(Lambda)).empty())
freevars->back().insert(id->location());
}
return NoChange;
}),
return NoChange;
}),
T(NLRCheck) << (T(Explicit) * T(Call)[Call]) >> ([](Match& _) -> Node {
// Mark NLRCheck inside a Lambda as Implicit, to prevent future
// unwrapping in the nlrcheck pass.
auto call = _(Call);
T(Lambda)[Lambda]
<< (T(TypeParams)[TypeParams] * T(Params)[Params] *
T(Type)[Type] * T(TypePred)[TypePred] * T(Block)[Block]) >>
[freevars](Match& _) {
// Create the anonymous type.
Node class_body = ClassBody;
auto class_id = _.fresh(l_lambda);
auto classdef = Class << (Ident ^ class_id) << TypeParams
<< (Inherit << DontCare) << typepred()
<< class_body;
if (
call->parent({Lambda, FieldLet, FieldVar, Param, Function})
->type() == Lambda)
return NLRCheck << Implicit << call;
// The create function will capture the free variables.
Node create_params = Params;
Node create_args = Tuple;
Node new_args = Tuple;
return NoChange;
}),
Node apply_body = Block;
auto self_id = _.fresh(l_self);
auto& fv = freevars->back();
T(Lambda)[Lambda]
<< (T(TypeParams)[TypeParams] * T(Params)[Params] * T(Type)[Type] *
T(TypePred)[TypePred] * T(Block)[Block]) >>
[freevars](Match& _) {
// Create the anonymous type.
Node class_body = ClassBody;
auto class_id = _.fresh(l_class);
auto classdef = Class << (Ident ^ class_id) << TypeParams
<< (Inherit << DontCare) << typepred()
<< class_body;
std::for_each(
fv.begin(), fv.end(), [&](auto& fv_id) {
// Add a field for the free variable to the anonymous type.
auto type_id = _.fresh(l_typevar);
class_body
<< (FieldLet << Explicit << (Ident ^ fv_id)
<< typevar(type_id) << DontCare);
// Build an FQType for the anonymous type.
auto fq = append_fq(
local_fq(_(Lambda)->parent({Class, Trait})),
TypeClassName << (Ident ^ class_id) << TypeArgs);
// Add a parameter to the create function to capture the free
// variable as a field.
create_params
<< (Param << (Ident ^ fv_id) << typevar(type_id)
<< DontCare);
new_args << (Expr << (RefLet << (Ident ^ fv_id)));
// The create function will capture the free variables.
auto fq_new = append_fq(fq, selector(l_new));
Node new_args = Tuple;
// Add an argument to the create call. Don't load the free
// variable, even if it was a `var`.
create_args << (Expr << (RefLet << (Ident ^ fv_id)));
auto fq_create = append_fq(fq, selector(l_create));
Node create_params = Params;
Node create_args = Tuple;
// At the start of the lambda body, assign the field to a
// local variable with the same name as the free variable.
apply_body
<< (Expr
<< (Assign << (Expr
<< (TypeAssert
<< (Expr << (Let << (Ident ^ fv_id)))
<< typevar(type_id)))
<< (Expr << (RefLet << (Ident ^ self_id))
<< Dot << selector(fv_id))));
});
Node apply_body = Block;
auto self_id = _.fresh(l_self);
auto& fv = freevars->back();
// The apply function is the original lambda. Prepend a
// `self`-like parameter with a fresh name to the lambda
// parameters.
// TODO: capability for Self
auto apply_func = Function
<< LambdaFunc << Rhs << (Ident ^ l_apply) << _(TypeParams)
<< (Params << (Param << (Ident ^ self_id) << (Type << Self)
<< DontCare)
<< *_[Params])
<< _(Type) << DontCare << _(TypePred)
<< (apply_body << *_[Block]);
std::for_each(
fv.begin(), fv.end(), [&](auto& fv_id) {
// Add a field for the free variable to the anonymous type.
auto type_id = _.fresh(l_typevar);
class_body
<< (FieldLet << (Ident ^ fv_id)
<< (Type << (TypeVar ^ type_id)) << DontCare);
// Add the create and apply functions to the anonymous type.
auto create_func = Function
<< Implicit << Rhs << (Ident ^ l_create) << TypeParams
<< create_params << typevar(_) << DontCare << typepred()
<< (Block << (Expr << New << tuple_to_args(new_args)));
// Add a parameter to the create function to capture the free
// variable as a field.
create_params
<< (Param << (Ident ^ fv_id) << (Type << (TypeVar ^ type_id))
<< DontCare);
new_args << (Expr << (RefLet << (Ident ^ fv_id)));
class_body << create_func << apply_func;
freevars->pop_back();
// Add an argument to the create call. Don't load the free
// variable, even if it was a `var`.
create_args << (Expr << (RefLet << (Ident ^ fv_id)));
// At the start of the lambda body, assign the field to a
// local variable with the same name as the free variable.
apply_body
<< (Expr
<< (Bind << (Ident ^ fv_id)
<< (Type << (TypeVar ^ type_id))
<< (Expr << call(
selector(fv_id),
RefLet << (Ident ^ self_id)))));
});
// The apply function is the original lambda. Prepend a
// `self`-like parameter with a fresh name to the lambda
// parameters.
// TODO: capability for Self
auto apply_func = Function
<< Implicit << Rhs << (Ident ^ l_apply) << _(TypeParams)
<< (Params << (Param << (Ident ^ self_id) << (Type << Self)
<< DontCare)
<< *_[Params])
<< _(Type) << DontCare << _(TypePred)
<< (apply_body << *_[Block]);
// Add the create and apply functions to the anonymous type.
auto create_func = Function
<< Implicit << Rhs << (Ident ^ l_create) << TypeParams
<< create_params << typevar(_) << DontCare << typepred()
<< (Block << (Expr << call(fq_new, new_args)));
class_body << create_func << apply_func;
freevars->pop_back();
return Seq << (Lift << ClassBody << classdef)
<< call(fq_create, create_args);
},
}};
return Seq << (Lift << Block << classdef)
<< (Expr << (Ident ^ class_id)
<< tuple_to_args(create_args));
},
}};
lambda.pre(Lambda, [freevars](Node) {
freevars->push_back({});

Просмотреть файл

@ -7,11 +7,11 @@ namespace verona
PassDef memberconflict()
{
return {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
(T(FieldLet) / T(FieldVar) / T(Function))[Op] >> ([](Match& _) -> Node {
T(FieldLet, FieldVar, Function)[Op] >> ([](Match& _) -> Node {
auto f = _(Op);
bool implicit = (f / Implicit)->type() == Implicit;
bool implicit = (f / Implicit) == Implicit;
auto defs = f->scope()->lookdown((f / Ident)->location());
Nodes conflicts;
@ -20,7 +20,7 @@ namespace verona
if (!conflict(f, def))
continue;
if (implicit == ((def / Implicit)->type() == Implicit))
if (implicit == ((def / Implicit) == Implicit))
{
// If both are implicit or both are explicit, it's an error.
if (def->precedes(f))
@ -44,7 +44,7 @@ namespace verona
Node e = Error;
auto p = f->parent({Class, Trait});
if (p->type() == Class)
if (p == Class)
e << (ErrorMsg ^ "Member conflict in this class")
<< (ErrorAst ^ (p / Ident));
else

Просмотреть файл

@ -35,22 +35,22 @@ namespace verona
// Otherwise end the type at a Where, Brace, or TripleColon.
T(Colon) *
(~T(Brace) *
(((T(Symbol) / T(Dot)) * T(Brace)) /
(!(T(Where) / T(Brace) / T(TripleColon))))++)[Type] >>
((T(Symbol, Dot) * T(Brace)) /
(!T(Where, Brace, TripleColon)))++)[Type] >>
[](Match& _) { return Type << (_[Type] || DontCare); },
// Type predicate.
T(Where) *
(~T(Brace) *
(((T(Symbol) / T(Dot)) * T(Brace)) /
(!(T(Where) / T(Brace) / T(TripleColon))))++)[Type] >>
((T(Symbol, Dot) * T(Brace)) /
(!T(Where, Brace, TripleColon)))++)[Type] >>
[](Match& _) { return TypePred << (Type << (_[Type] || TypeTrue)); },
T(TripleColon) *
(T(Paren)
<< ((T(List) << (T(Group) << (T(Ident) / T(LLVM)))++[Args]) /
~(T(Group) << (T(Ident) / T(LLVM)))[Args])) *
T(Symbol, "->") * (T(Ident) / T(LLVM))[Return] >>
<< ((T(List) << (T(Group) << T(Ident, LLVM))++[Args]) /
~(T(Group) << T(Ident, LLVM))[Args])) *
T(Symbol, "->") * T(Ident, LLVM)[Return] >>
[](Match& _) {
return LLVMFuncType << (LLVMList << *_[Args]) << _(Return);
},

Просмотреть файл

@ -7,12 +7,10 @@ namespace verona
PassDef nlrcheck()
{
return {
dir::topdown | dir::once,
dir::bottomup | dir::once,
{
T(NLRCheck)
<< (IsImplicit[Implicit] *
(T(Call)[Call]
<< ((T(Selector) / T(FQFunction))[Op] * T(Args)))) >>
<< (T(Call)[Call] << (T(Selector, FQFunction)[Op] * T(Args))) >>
[](Match& _) {
auto call = _(Call);
@ -27,10 +25,10 @@ namespace verona
auto nlr = Type << nonlocal(_);
Node ret = Cast << ref << nlr;
// Unwrap if we're in a function (Explicit), but not if we're in a
// lambda (Implicit).
if (_(Implicit)->type() == Explicit)
ret = load(ret, true);
// Unwrap if we're in a function, but not if we're in a lambda.
// Remove the NLRCheck around the load call.
if (call->parent(Function) / Implicit != LambdaFunc)
ret = load(ret) / Call;
return ExprSeq << (Expr
<< (Bind << (Ident ^ id) << typevar(_)

Просмотреть файл

@ -11,7 +11,7 @@ namespace verona
// This function extracts all typeparams from a type `t` that are defined
// within `scope` and appends them to `tp` if they aren't already present.
if (t->type().in(
if (t->in(
{Type,
TypeArgs,
TypeUnion,
@ -23,17 +23,17 @@ namespace verona
for (auto& tt : *t)
extract_typeparams(scope, tt, tp);
}
else if (t->type().in({TypeClassName, TypeAliasName, TypeTraitName}))
else if (t->in({TypeClassName, TypeAliasName, TypeTraitName}))
{
extract_typeparams(scope, t / Lhs, tp);
extract_typeparams(scope, t / TypeArgs, tp);
}
else if (t->type() == TypeParamName)
else if (t == TypeParamName)
{
auto id = t / Ident;
auto defs = id->lookup(scope);
if ((defs.size() == 1) && ((*defs.begin())->type() == TypeParam))
if ((defs.size() == 1) && ((*defs.begin()) == TypeParam))
{
if (!std::any_of(tp->begin(), tp->end(), [&](auto& p) {
return (p / Ident)->location() == id->location();
@ -52,7 +52,7 @@ namespace verona
{
// This finds all typeparams in a Class or Function definition and builds
// a TypeArgs that contains all of them, in order.
if (!node->type().in({Class, Function}))
if (!node->in({Class, Function}))
return typeargs;
for (auto typeparam : *(node / TypeParams))
@ -82,15 +82,13 @@ namespace verona
T(Function)[Function]
<< (IsImplicit * Hand[Ref] * T(Ident)[Ident] *
T(TypeParams)[TypeParams] * T(Params)[Params] * T(Type) *
T(DontCare) * T(TypePred)[TypePred] *
(T(Block) / T(DontCare))) >>
[](Match& _) {
T(DontCare) * T(TypePred)[TypePred] * T(Block, DontCare)) >>
([](Match& _) -> Node {
auto f = _(Function);
auto parent = f->parent({Class, Trait});
auto hand = _(Ref)->type();
auto id = _(Ident);
auto params = _(Params);
auto parent = f->parent({Class, Trait});
auto fq_f = local_fq(f);
auto fq_parent = local_fq(parent);
// Find the lowest arity that is not already defined. If an arity 5
// and an arity 3 function `f` are provided, an arity 4 partial
@ -103,7 +101,7 @@ namespace verona
for (auto def : defs)
{
if ((def == f) || (def->type() != Function))
if ((def == f) || (def != Function))
continue;
auto arity = (def / Params)->size();
@ -112,14 +110,61 @@ namespace verona
start_arity = std::max(start_arity, arity + 1);
}
if (start_arity == end_arity)
return NoChange;
// We will be returning the original function, plus some number of
// partial application functions and their anonymous classes. Make
// the local FQ before putting `f` into the Seq node.
auto fq_f = local_fq(f);
Node ret = Seq << f;
// If the parent is a trait, generate the partial application
// function prototypes, but no implementations.
if (parent == Trait)
{
for (auto arity = start_arity; arity < end_arity; ++arity)
{
Node func_tp = TypeParams;
Node func_params = Params;
for (size_t i = 0; i < arity; ++i)
{
auto param = params->at(i);
auto param_id = param / Ident;
auto param_type = param / Type;
// Add any needed typeparams.
extract_typeparams(f, param_type, func_tp);
// Add the parameter to the partial function.
func_params << clone(param);
}
ret
<< (Function << Implicit << hand << clone(id) << func_tp
<< func_params << typevar(_) << DontCare
<< typepred() << DontCare);
}
return ret;
}
// Create a unique anonymous class name for each arity.
Nodes names;
auto basename = std::string("partial.")
.append(hand.str())
.append(".")
.append(id->location().view())
.append("/");
for (auto arity = start_arity; arity < end_arity; ++arity)
names.push_back(Ident ^ _.fresh(l_class));
{
names.push_back(
Ident ^ _.fresh(basename + std::to_string(arity)));
}
Node ret = Seq << f;
auto hand = _(Ref)->type();
auto fq_parent = local_fq(parent);
Nodes fqs;
Nodes classbodies;
@ -141,6 +186,7 @@ namespace verona
// The anonymous class has fields for each supplied argument and a
// create function that captures the supplied arguments.
auto fq_new = append_fq(fq_class, selector(l_new));
Node new_params = Params;
Node new_args = Tuple;
// Find all needed typeparams and add them.
@ -169,6 +215,7 @@ namespace verona
// Add the argument to the `new` call inside the class create
// function.
new_args << (Expr << (RefLet << clone(param_id)));
new_params << (Param << clone(param_id) << clone(param_type));
// Add the parameter to the partial function.
func_params << clone(param);
@ -184,6 +231,12 @@ namespace verona
<< (Block << (Expr << call(fq_new, new_args)));
classbody << create_func;
// Create the `new` function.
classbody
<< (Function << Explicit << Rhs << (Ident ^ l_new) << TypeParams
<< new_params << typevar(_) << DontCare
<< typepred() << (Block << (Expr << unit())));
// Create the partial function that returns the anonymous class.
auto fq_create = append_fq(
fq_class,
@ -266,7 +319,7 @@ namespace verona
}
return ret;
},
}),
}};
}
}

Просмотреть файл

@ -11,10 +11,9 @@ namespace verona
// LLVM literal.
In(Expr) * T(LLVM)[LLVM] * T(Ident)[Lhs] * T(Ident)++[Rhs] >>
[](Match& _) {
auto llvm = _(LLVM);
auto rhs = _[Rhs];
auto s = std::string()
.append(llvm->location().view())
.append(_(LLVM)->location().view())
.append(" %")
.append(_(Lhs)->location().view());
@ -33,134 +32,30 @@ namespace verona
.append(_(Rhs)->location().view());
},
// Dot notation. Use `Ident` as a selector, even if it's in scope.
In(Expr) * T(Dot) * (T(Ident) / T(Symbol))[Ident] *
// Dot and DoubleColon notation. Use `Ident` as a selector, even if it's
// in scope.
In(Expr) * T(Dot, DoubleColon)[Dot] * T(Ident, Symbol)[Ident] *
~T(TypeArgs)[TypeArgs] >>
[](Match& _) { return Seq << Dot << selector(_(Ident), _(TypeArgs)); },
[](Match& _) {
return Seq << _(Dot) << selector(_(Ident), _(TypeArgs));
},
// Local reference.
In(Expr) *
T(Ident)[Ident]([](auto& n) { return lookup_type(n, {Var}); }) >>
[](Match& _) { return RefVar << _(Ident); },
In(Expr) * T(Ident)[Ident] >> ([](Match& _) -> Node {
auto id = _(Ident);
In(Expr) * T(Ident)[Ident]([](auto& n) {
return lookup_type(n, {Let, Param});
}) >>
[](Match& _) { return RefLet << _(Ident); },
if (lookup_type(id, {Var}))
return RefVar << id;
else if (lookup_type(id, {Let, Param}))
return RefLet << id;
// Unscoped reference.
In(Expr) * (T(Ident) / T(Symbol))[Ident] * ~T(TypeArgs)[TypeArgs] >>
return NoChange;
}),
// Given `try { ... }`, apply the lambda.
In(Expr) * T(Try)[Try] * T(Lambda)[Lambda] * --T(Dot) >>
[](Match& _) {
auto id = _(Ident);
auto ta = _(TypeArgs);
auto defs = lookup(id, ta);
if (defs.size() == 1)
{
auto def = *defs.begin();
if (def.too_many_typeargs)
{
return Error << (ErrorMsg ^ "too many type arguments")
<< ((ErrorAst ^ id) << id << ta);
}
auto fq = make_fq(def);
if (fq->type() == FQType)
return fq;
}
if (defs.size() > 1)
{
// If there are multiple definitions, it's an ambiguous reference.
auto err = Error << (ErrorMsg ^ "ambiguous reference")
<< ((ErrorAst ^ id) << id << ta);
for (auto& other : defs)
err << (ErrorAst ^ (other.def / Ident));
return err;
}
// If there isn't a single type definition, treat it as a selector.
return selector(id, ta);
},
// Scoped reference.
In(Expr) *
(T(FQType)[Lhs] * T(DoubleColon) * (T(Ident) / T(Symbol))[Ident] *
~T(TypeArgs)[TypeArgs]) >>
[](Match& _) {
auto id = _(Ident);
auto ta = _(TypeArgs);
auto def = resolve_fq(_(Lhs));
auto defs = lookdown(def, id, ta);
if (defs.size() == 0)
return Error << (ErrorMsg ^ "unknown reference")
<< ((ErrorAst ^ id) << id << ta);
if (defs.size() == 1)
{
auto ldef = *defs.begin();
if (ldef.too_many_typeargs)
{
return Error << (ErrorMsg ^ "too many type arguments")
<< ((ErrorAst ^ id) << id << ta);
}
return make_fq(ldef);
}
if (std::any_of(defs.begin(), defs.end(), [](auto& d) {
return d.def->type() != Function;
}))
{
// If there are multiple definitions, and at least one of them is
// not a function, then we have an ambiguous reference.
auto err = Error << (ErrorMsg ^ "ambiguous reference")
<< ((ErrorAst ^ id) << id << ta);
for (auto& other : defs)
err << (ErrorAst ^ (other.def / Ident));
return err;
}
// Select the smallest arity function.
auto l =
*std::min_element(defs.begin(), defs.end(), [](auto& a, auto& b) {
return (a.def / Params)->size() < (b.def / Params)->size();
});
return make_fq(l);
},
// Error out on invalid scoped references.
In(Expr) *
(T(DoubleColon) * ~(T(Ident) / T(Symbol)) *
~T(TypeArgs))[DoubleColon] >>
[](Match& _) {
return err(_(DoubleColon), "Expected a scoped reference");
},
// Create sugar, with no arguments.
In(Expr) * T(FQType)[FQType] * ~T(TypeArgs)[TypeArgs] >>
[](Match& _) {
return append_fq(_(FQType), selector(l_create, _(TypeArgs)));
},
// Lone TypeArgs are typeargs on apply.
In(Expr) * T(TypeArgs)[TypeArgs] >>
[](Match& _) { return Seq << Dot << selector(l_apply, _(TypeArgs)); },
// New sugar.
In(Expr) * T(New)[New] >>
[](Match& _) {
return append_fq(
local_fq(_(New)->parent({Class, Trait})), selector(l_new));
return Seq << Try << _(Lambda) << Dot << selector(l_apply);
},
};
}

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright Microsoft and Project Verona Contributors.
// SPDX-License-Identifier: MIT
#include "../lang.h"
namespace verona
{
PassDef resetimplicit()
{
return {
dir::bottomup | dir::once,
{
// Reset everything marked as implicit to be explicit.
T(Implicit) >> ([](Match&) -> Node { return Explicit; }),
// Strip implicit/explicit marker from fields.
T(FieldLet) << (IsImplicit * T(Ident)[Ident] * T(Type)[Type]) >>
[](Match& _) { return FieldLet << _(Ident) << _(Type); },
T(FieldVar) << (IsImplicit * T(Ident)[Ident] * T(Type)[Type]) >>
[](Match& _) { return FieldVar << _(Ident) << _(Type); },
// Remove all `use` statements.
In(ClassBody) * T(Use) >> ([](Match&) -> Node { return {}; }),
In(Block) * T(Use) >> ([](Match&) -> Node { return Expr << Unit; }),
}};
}
}

Просмотреть файл

@ -7,10 +7,6 @@ namespace verona
PassDef reverseapp()
{
return {
// Remove all `use` statements.
In(ClassBody) * T(Use) >> ([](Match&) -> Node { return {}; }),
In(Block) * T(Use) >> ([](Match&) -> Node { return Expr << Unit; }),
// Dot: reverse application. This binds most strongly.
(Object / Operator)[Lhs] * T(Dot) * Operator[Rhs] >>
[](Match& _) { return call(_(Rhs), _(Lhs)); },

Просмотреть файл

@ -8,7 +8,7 @@ namespace verona
{
if (!name)
name = Ident ^ l_apply;
else if (name->type() == Symbol)
else if (name == Symbol)
name = Ident ^ name;
return name;
@ -22,25 +22,22 @@ namespace verona
In(ClassBody) *
(T(Equals)
<< ((T(Group)
<< ((T(Let) / T(Var))[Let] * T(Ident)[Ident] * ~T(Type)[Type] *
<< (T(Let, Var)[Let] * T(Ident)[Ident] * ~T(Type)[Type] *
End)) *
T(Group)++[Rhs])) >>
[](Match& _) {
Node node = _(Let)->type() == Let ? FieldLet : FieldVar;
Node node = _(Let) == Let ? FieldLet : FieldVar;
return node << Explicit << _(Ident) << typevar(_, Type)
<< (Lambda << TypeParams << Params << typevar(_)
<< typepred()
<< (Block << (Expr << (Default << _[Rhs]))));
<< (Block << (Expr << (Default << _[Rhs])));
},
// Field without a default value.
// (group let|var ident type)
In(ClassBody) *
(T(Group)
<< ((T(Let) / T(Var))[Let] * T(Ident)[Ident] * ~T(Type)[Type] *
End)) >>
<< (T(Let, Var)[Let] * T(Ident)[Ident] * ~T(Type)[Type] * End)) >>
[](Match& _) {
Node node = _(Let)->type() == Let ? FieldLet : FieldVar;
Node node = _(Let) == Let ? FieldLet : FieldVar;
return node << Explicit << _(Ident) << typevar(_, Type) << DontCare;
},
@ -50,7 +47,7 @@ namespace verona
In(ClassBody) *
(T(Equals)
<< ((T(Group)
<< (~T(Ref)[Ref] * ~(T(Ident) / T(Symbol))[Ident] *
<< (~T(Ref)[Ref] * ~T(Ident, Symbol)[Ident] *
~T(Square)[TypeParams] * T(Paren)[Params] * ~T(Type)[Type] *
~T(LLVMFuncType)[LLVMFuncType] * ~T(TypePred)[TypePred] *
T(Brace)[Block] * (Any * Any++)[Lhs])) *
@ -71,7 +68,7 @@ namespace verona
In(ClassBody) *
(T(Equals)
<< ((T(Group)
<< (~T(Ref)[Ref] * ~(T(Ident) / T(Symbol))[Ident] *
<< (~T(Ref)[Ref] * ~T(Ident, Symbol)[Ident] *
~T(Square)[TypeParams] * T(Paren)[Params] * ~T(Type)[Type] *
~T(LLVMFuncType)[LLVMFuncType] * ~T(TypePred)[TypePred] *
End)) *
@ -89,8 +86,8 @@ namespace verona
// Function: f[T](x: T = e): T { e }
// (group name typeparams params type llvmtype typepred brace)
In(ClassBody) * T(Group)
<< (~T(Ref)[Ref] * ~(T(Ident) / T(Symbol))[Ident] *
~T(Square)[TypeParams] * T(Paren)[Params] * ~T(Type)[Type] *
<< (~T(Ref)[Ref] * ~T(Ident, Symbol)[Ident] * ~T(Square)[TypeParams] *
T(Paren)[Params] * ~T(Type)[Type] *
~T(LLVMFuncType)[LLVMFuncType] * ~T(TypePred)[TypePred] *
~T(Brace)[Block] * (Any++)[Rhs]) >>
[](Match& _) {
@ -129,10 +126,10 @@ namespace verona
T(Group)++[Rhs]) >>
[](Match& _) {
return ValueParam << _(Ident) << _(Type)
<< (Expr << (Default << _[Rhs]));
<< (Block << (Expr << (Default << _[Rhs])));
},
In(TypeParams) * (!(T(TypeParam) / T(ValueParam)))[TypeParam] >>
In(TypeParams) * (!T(TypeParam, ValueParam))[TypeParam] >>
[](Match& _) {
return err(
_(TypeParam), "Expected a type parameter or a value parameter");
@ -149,34 +146,29 @@ namespace verona
// Param: (group ident type)
In(Params) * T(Group)
<< ((T(Ident) / T(DontCare))[Ident] * ~T(Type)[Type] * End) >>
<< (T(Ident, DontCare)[Ident] * ~T(Type)[Type] * End) >>
[](Match& _) {
auto id = (_(Ident)->type() == DontCare) ?
(Ident ^ _.fresh(l_param)) :
_(Ident);
auto id =
(_(Ident) == DontCare) ? (Ident ^ _.fresh(l_param)) : _(Ident);
return Param << id << typevar(_, Type) << DontCare;
},
// Param: (equals (group ident type) group)
In(Params) * T(Equals)
<< ((T(Group)
<< ((T(Ident) / T(DontCare))[Ident] * ~T(Type)[Type] * End)) *
<< ((T(Group) << (T(Ident, DontCare)[Ident] * ~T(Type)[Type] * End)) *
T(Group)++[Expr]) >>
[](Match& _) {
auto id = (_(Ident)->type() == DontCare) ?
(Ident ^ _.fresh(l_param)) :
_(Ident);
auto id =
(_(Ident) == DontCare) ? (Ident ^ _.fresh(l_param)) : _(Ident);
return Param << id << typevar(_, Type)
<< (Lambda << TypeParams << Params << typevar(_)
<< typepred()
<< (Block << (Expr << (Default << _[Expr]))));
<< (Block << (Expr << (Default << _[Expr])));
},
In(Params) * (!T(Param))[Param] >>
[](Match& _) { return err(_(Param), "Expected a parameter"); },
// Use.
(In(ClassBody) / In(Block)) * T(Group) << T(Use)[Use] * (Any++)[Type] >>
In(ClassBody, Block) * T(Group) << T(Use)[Use] * (Any++)[Type] >>
[](Match& _) {
return (Use ^ _(Use)) << (Type << (_[Type] || DontCare));
},
@ -185,7 +177,7 @@ namespace verona
[](Match& _) { return err(_(Use), "Can't put a `use` here"); },
// TypeAlias: (equals (group typealias typeparams typepred) group)
(In(ClassBody) / In(Block)) * T(Equals)
In(ClassBody, Block) * T(Equals)
<< ((T(Group)
<< (T(TypeAlias) * T(Ident)[Ident] * ~T(Square)[TypeParams] *
~T(TypePred)[TypePred] * End)) *
@ -196,7 +188,7 @@ namespace verona
<< (Type << (Default << _[Rhs]));
},
(In(ClassBody) / In(Block)) * T(TypeAlias)[TypeAlias] << End >>
In(ClassBody, Block) * T(TypeAlias)[TypeAlias] << End >>
[](Match& _) {
return err(_(TypeAlias), "Expected a `type` definition");
},
@ -207,7 +199,7 @@ namespace verona
// Class.
// (group class ident typeparams type typepred brace ...)
(In(Top) / In(ClassBody) / In(Block)) * T(Group)
In(Top, ClassBody, Block) * T(Group)
<< (T(Class) * T(Ident)[Ident] * ~T(Square)[TypeParams] *
~T(Type)[Type] * ~T(TypePred)[TypePred] * T(Brace)[ClassBody] *
(Any++)[Rhs]) >>
@ -218,7 +210,7 @@ namespace verona
<< (Group << _[Rhs]);
},
(In(Top) / In(ClassBody) / In(Block)) * T(Class)[Class] << End >>
In(Top, ClassBody, Block) * T(Class)[Class] << End >>
[](Match& _) { return err(_(Class), "Expected a `class` definition"); },
T(Class)[Class] << End >>
[](Match& _) {
@ -236,7 +228,7 @@ namespace verona
// Type structure.
TypeStruct * T(Group)[Type] >> [](Match& _) { return Type << *_[Type]; },
TypeStruct * (T(List) / T(Paren))[TypeTuple] >>
TypeStruct * T(List, Paren)[TypeTuple] >>
[](Match& _) { return Type << (TypeTuple << *_[TypeTuple]); },
// Anonymous structural types.
@ -247,28 +239,38 @@ namespace verona
},
// Strings in types are package descriptors.
TypeStruct * (T(String) / T(Escaped))[Package] >>
TypeStruct * T(String, Escaped)[Package] >>
[](Match& _) { return Package << _(Package); },
TypeStruct *
(T(Equals) / T(Arrow) / T(Use) / T(Class) / T(TypeAlias) / T(Var) /
T(Let) / T(Ref) / T(If) / T(Else) / T(New) / T(Try) /
T(LLVMFuncType) / Literal)[Type] >>
(T(Equals,
Arrow,
Use,
Class,
TypeAlias,
Var,
Let,
Ref,
If,
Else,
New,
Try,
LLVMFuncType) /
Literal)[Type] >>
[](Match& _) { return err(_(Type), "Can't put this in a type"); },
// A group can be in a Block, Expr, ExprSeq, Tuple, or Assign.
(In(Block) / In(Expr) / In(ExprSeq) / In(Tuple) / In(Assign)) *
T(Group)[Group] >>
In(Block, Expr, ExprSeq, Tuple, Assign) * T(Group)[Group] >>
[](Match& _) { return Expr << *_[Group]; },
// An equals can be in a Block, ExprSeq, Tuple, or Expr.
(In(Block) / In(ExprSeq) / In(Tuple)) * T(Equals)[Equals] >>
In(Block, ExprSeq, Tuple) * T(Equals)[Equals] >>
[](Match& _) { return Expr << (Assign << *_[Equals]); },
In(Expr) * T(Equals)[Equals] >>
[](Match& _) { return Assign << *_[Equals]; },
// A list can be in a Block, ExprSeq, or Expr.
(In(Block) / In(ExprSeq)) * T(List)[List] >>
In(Block, ExprSeq) * T(List)[List] >>
[](Match& _) { return Expr << (Tuple << *_[List]); },
In(Expr) * T(List)[List] >> [](Match& _) { return Tuple << *_[List]; },
@ -308,7 +310,7 @@ namespace verona
// Object literal.
In(Expr) * T(New) * T(Brace)[ClassBody] >>
[](Match& _) {
auto class_id = _.fresh(l_class);
auto class_id = _.fresh(l_objlit);
return Seq << (Lift << Block
<< (Class << (Ident ^ class_id) << TypeParams
<< inherit() << typepred()
@ -334,8 +336,7 @@ namespace verona
// (brace (list|group) (group arrow) ...)
In(Expr) *
(T(Brace)
<< ((T(List) / T(Group))[Params] * (T(Group) << T(Arrow)) *
Any++[Rhs])) >>
<< (T(List, Group)[Params] * (T(Group) << T(Arrow)) * Any++[Rhs])) >>
[](Match& _) {
return Lambda << TypeParams << (Params << _[Params]) << typevar(_)
<< typepred() << (Block << _[Rhs]);
@ -371,7 +372,7 @@ namespace verona
[](Match& _) { return Expr << Ref << *_[Expr]; },
// Lift Use, Class, TypeAlias to Block.
In(Expr) * (T(Use) / T(Class) / T(TypeAlias))[Lift] >>
In(Expr) * T(Use, Class, TypeAlias)[Lift] >>
[](Match& _) { return Lift << Block << _[Lift]; },
// A Type at the end of an Expr is a TypeAssert. A tuple is never directly
@ -381,9 +382,7 @@ namespace verona
return Expr << (TypeAssert << (Expr << _[Expr]) << _(Type));
},
In(Expr) *
(TypeCaps / T(TypePred) / T(Self) / T(Arrow) /
T(LLVMFuncType))[Expr] >>
In(Expr) * (TypeCaps / T(TypePred, Arrow, LLVMFuncType))[Expr] >>
[](Match& _) {
return err(_(Expr), "Can't put this in an expression");
},

Просмотреть файл

@ -10,21 +10,21 @@ namespace verona
// late so that fields have already been turned into accessor functions and
// partial application functions have already been generated.
return {
dir::once | dir::topdown,
dir::bottomup | dir::once,
{
T(Trait)[Trait] << (T(Ident)[Ident] * T(ClassBody)[ClassBody]) >>
[](Match& _) {
// If we're inside a TypeIsect, put the new traits inside it.
// Otherwise, create a new TypeIsect.
Node r =
(_(Trait)->parent()->type() == TypeIsect) ? Seq : TypeIsect;
(_(Trait)->parent() == TypeIsect) ? Seq : TypeIsect;
Node base = ClassBody;
r << (Trait << _(Ident) << base);
for (auto& member : *_(ClassBody))
{
if (member->type() == Function)
if (member == Function)
{
// Strip any default implementation.
(member / Block) = DontCare;

186
src/passes/typeinfer.cc Normal file
Просмотреть файл

@ -0,0 +1,186 @@
// Copyright Microsoft and Project Verona Contributors.
// SPDX-License-Identifier: MIT
#include "../lang.h"
#include "../subtype.h"
namespace verona
{
Node gamma(Node node)
{
// TODO: Move vs Copy type.
// when testing, this may not resolve
return (node / Ident)->lookup().front() / Type;
}
struct Infer
{
Bounds& bounds;
Node cls;
Btype ret_type;
Btype bool_type;
Infer(Node f, Bounds& b) : bounds(b)
{
cls = f->parent(Class);
ret_type = make_btype(f / Type);
bool_type = make_btype(booltype());
check(do_block(f / Block), ret_type);
}
void check(Btype ltype, Btype rtype)
{
if (!subtype(ltype, rtype, bounds))
{
// TODO:
std::cout << "subtype failed" << std::endl
<< "---" << std::endl
<< ltype << "---" << std::endl
<< rtype;
}
}
void check(Node ltype, Btype rtype)
{
if (ltype)
check(make_btype(ltype), rtype);
}
Node do_block(Node& block)
{
for (auto stmt : *block)
{
if (stmt == Bind)
{
// TODO: literals
auto rhs = stmt / Rhs;
auto type = make_btype(stmt / Type);
if (rhs == TypeTest)
check(bool_type, type);
else if (rhs == Cast)
check(rhs / Type, type);
else if (rhs->in({Move, Copy}))
check(gamma(rhs), type);
else if (rhs == FieldRef)
{
// TODO: Self substitution?
// this is failing when `type` is a TypeVar, unclear why
check(
TypeView << -gamma(rhs / Ref)
<< reftype(
cls->lookdown((rhs / Ident)->location()).front() /
Type),
type);
}
else if (rhs == Conditional)
{
check(gamma(rhs / If), bool_type);
check(do_block(rhs / True), type);
check(do_block(rhs / False), type);
}
else if (rhs == Call)
{
auto sel = rhs / Selector;
if (sel == FQFunction)
{
// TODO: may not have a function of this arity
auto l = resolve_fq(sel);
auto params = clone(l.def / Params);
auto ret = clone(l.def / Type);
auto args = rhs / Args;
l.sub(params);
l.sub(ret);
(void)std::equal(
params->begin(),
params->end(),
args->begin(),
args->end(),
[&](Node& param, Node& arg) {
check(gamma(arg), make_btype(param / Type));
return true;
});
check(ret, type);
}
else
{
// TODO: selector
}
}
else if (rhs->in(
{Int,
Bin,
Oct,
Hex,
Float,
HexFloat,
Char,
Escaped,
String,
Tuple,
LLVM}))
{
// TODO:
}
else
{
assert(false);
}
}
else if (stmt == Return)
{
assert(stmt == block->back());
check(gamma(stmt / Ref), ret_type);
}
else if (stmt == Move)
{
assert(stmt == block->back());
return gamma(stmt);
}
else
{
assert(stmt->in({Class, TypeAlias, LLVM, Drop}));
}
}
return {};
}
};
PassDef typeinfer()
{
auto bounds = std::make_shared<Bounds>();
PassDef typeinfer = {
dir::bottomup | dir::once,
{
T(Function)[Function] >> ([=](Match& _) -> Node {
Infer infer(_(Function), *bounds);
return NoChange;
}),
}};
typeinfer.post([=](Node) {
for (auto& [typevar, bound] : *bounds)
{
std::cout << typevar.view() << std::endl << "--lower--" << std::endl;
for (auto& b : bound.lower)
std::cout << b << std::endl;
std::cout << "--upper--" << std::endl;
for (auto& b : bound.upper)
std::cout << b << std::endl;
std::cout << "--done--" << std::endl;
}
return 0;
});
return typeinfer;
}
}

Просмотреть файл

@ -32,7 +32,7 @@ namespace verona
auto fq = make_fq(def);
if (fq->type() != FQType)
if (fq != FQType)
return Error << (ErrorMsg ^ "type name is not a type")
<< ((ErrorAst ^ id) << id << ta);

124
src/passes/typereference.cc Normal file
Просмотреть файл

@ -0,0 +1,124 @@
// Copyright Microsoft and Project Verona Contributors.
// SPDX-License-Identifier: MIT
#include "../lang.h"
#include "../lookup.h"
namespace verona
{
PassDef typereference()
{
return {
// Unscoped reference.
In(Expr) * T(Ident, Symbol, Self)[Ident] * ~T(TypeArgs)[TypeArgs] >>
[](Match& _) {
auto id = _(Ident);
auto ta = _(TypeArgs);
auto defs = lookup(id, ta);
if (defs.size() == 1)
{
auto def = *defs.begin();
if (def.too_many_typeargs)
{
return Error << (ErrorMsg ^ "too many type arguments")
<< ((ErrorAst ^ id) << id << ta);
}
auto fq = make_fq(def);
if (fq == FQType)
return fq;
}
if (defs.size() > 1)
{
// If there are multiple definitions, it's an ambiguous reference.
auto err = Error << (ErrorMsg ^ "ambiguous reference")
<< ((ErrorAst ^ id) << id << ta);
for (auto& other : defs)
err << (ErrorAst ^ (other.def / Ident));
return err;
}
// If there isn't a single type definition, treat it as a selector.
return selector(id, ta);
},
// Scoped reference.
In(Expr) * T(FQType)[Lhs] * T(DoubleColon) * T(Selector)[Selector] >>
[](Match& _) {
auto sel = _(Selector);
auto id = sel / Ident;
auto ta = sel / TypeArgs;
auto def = resolve_fq(_(Lhs));
auto defs = lookdown(def, id, ta);
if (defs.size() == 0)
return Error << (ErrorMsg ^ "unknown reference")
<< ((ErrorAst ^ id) << id << ta);
if (defs.size() == 1)
{
auto ldef = *defs.begin();
if (ldef.too_many_typeargs)
{
return Error << (ErrorMsg ^ "too many type arguments")
<< ((ErrorAst ^ id) << id << ta);
}
return make_fq(ldef);
}
if (std::any_of(defs.begin(), defs.end(), [](auto& d) {
return d.def != Function;
}))
{
// If there are multiple definitions, and at least one of them is
// not a function, then we have an ambiguous reference.
auto err = Error << (ErrorMsg ^ "ambiguous reference")
<< ((ErrorAst ^ id) << id << ta);
for (auto& other : defs)
err << (ErrorAst ^ (other.def / Ident));
return err;
}
// Select the smallest arity function.
auto l =
*std::min_element(defs.begin(), defs.end(), [](auto& a, auto& b) {
return (a.def / Params)->size() < (b.def / Params)->size();
});
return make_fq(l);
},
// Error out on invalid scoped references.
In(Expr) * T(DoubleColon)[DoubleColon] >>
[](Match& _) {
return err(_(DoubleColon), "Expected a scoped reference");
},
// Lone TypeArgs are typeargs on apply.
In(Expr) * T(TypeArgs)[TypeArgs] >>
[](Match& _) { return Seq << Dot << selector(l_apply, _(TypeArgs)); },
// Create sugar, with no arguments.
In(Expr) * T(FQType)[FQType] * ~T(TypeArgs)[TypeArgs] >>
[](Match& _) {
return append_fq(_(FQType), selector(l_create, _(TypeArgs)));
},
// New sugar.
In(Expr) * T(New)[New] >>
[](Match& _) {
return append_fq(
local_fq(_(New)->parent({Class, Trait})), selector(l_new));
},
};
}
}

Просмотреть файл

@ -8,7 +8,7 @@ namespace verona
{
// This detects cycles in type aliases, which are not allowed. This happens
// after type names are turned into FQType.
assert(node->type() == TypeAlias);
assert(node == TypeAlias);
// Each element in the worklist carries a set of nodes that have been
// visited, a type node, and a map of typeparam bindings.
@ -22,19 +22,16 @@ namespace verona
auto& lookup = work.second;
worklist.pop_back();
if (lookup.def->type() == Type)
if (lookup.def == Type)
{
worklist.emplace_back(set, lookup.make(lookup.def / Type));
}
else if (lookup.def->type().in(
{TypeTuple, TypeUnion, TypeIsect, TypeView}))
else if (lookup.def->in({TypeTuple, TypeUnion, TypeIsect, TypeView}))
{
for (auto& t : *lookup.def)
worklist.emplace_back(set, lookup.make(t));
}
else if (
(lookup.def->type() == FQType) &&
((lookup.def / Type)->type() == TypeAliasName))
else if ((lookup.def == FQType) && ((lookup.def / Type) == TypeAliasName))
{
auto l = resolve_fq(lookup.def);
@ -47,9 +44,7 @@ namespace verona
worklist.emplace_back(set, l);
}
}
else if (
(lookup.def->type() == FQType) &&
((lookup.def / Type)->type() == TypeParamName))
else if ((lookup.def == FQType) && ((lookup.def / Type) == TypeParamName))
{
auto l = resolve_fq(lookup.def);
@ -68,7 +63,7 @@ namespace verona
bool recursive_inherit(Node node)
{
assert(node->type() == Inherit);
assert(node == Inherit);
std::vector<std::pair<NodeSet, Lookup>> worklist;
worklist.emplace_back(NodeSet{node}, node / Inherit);
@ -79,18 +74,16 @@ namespace verona
auto& lookup = work.second;
worklist.pop_back();
if (lookup.def->type() == Type)
if (lookup.def == Type)
{
worklist.emplace_back(set, lookup.make(lookup.def / Type));
}
else if (lookup.def->type() == TypeIsect)
else if (lookup.def == TypeIsect)
{
for (auto& t : *lookup.def)
worklist.emplace_back(set, lookup.make(t));
}
else if (
(lookup.def->type() == FQType) &&
((lookup.def / Type)->type() == TypeClassName))
else if ((lookup.def == FQType) && ((lookup.def / Type) == TypeClassName))
{
auto l = resolve_fq(lookup.def);
@ -98,25 +91,21 @@ namespace verona
{
Node inherit = l.def / Inherit;
if ((inherit->type() != Inherit) || set.contains(inherit))
if ((inherit != Inherit) || set.contains(inherit))
return true;
set.insert(inherit);
worklist.emplace_back(set, inherit / Inherit);
}
}
else if (
(lookup.def->type() == FQType) &&
((lookup.def / Type)->type() == TypeAliasName))
else if ((lookup.def == FQType) && ((lookup.def / Type) == TypeAliasName))
{
auto l = resolve_fq(lookup.def);
if (l.def)
worklist.emplace_back(set, l);
}
else if (
(lookup.def->type() == FQType) &&
((lookup.def / Type)->type() == TypeParamName))
else if ((lookup.def == FQType) && ((lookup.def / Type) == TypeParamName))
{
auto l = resolve_fq(lookup.def);
@ -140,7 +129,7 @@ namespace verona
// that expand to predicates.
Btype t = make_btype(fq);
if (t->type() != TypeAlias)
if (t != TypeAlias)
return false;
Btypes worklist;
@ -151,20 +140,20 @@ namespace verona
t = worklist.back();
worklist.pop_back();
if (t->type() == TypeSubtype)
if (t == TypeSubtype)
{
// Do nothing.
}
else if (t->type().in({TypeUnion, TypeIsect}))
else if (t->in({TypeUnion, TypeIsect}))
{
// Check that all children are valid predicates.
std::for_each(t->node->begin(), t->node->end(), [&](auto& n) {
worklist.push_back(t->make(n));
});
}
else if (t->type() == TypeAlias)
else if (t == TypeAlias)
{
worklist.push_back(t->field(Type));
worklist.push_back(t / Type);
}
else
{
@ -182,7 +171,7 @@ namespace verona
// valid inherit clauses.
Btype t = make_btype(fq);
if (!t->type().in({Class, Trait, TypeAlias}))
if (!t->in({Class, Trait, TypeAlias}))
return false;
Btypes worklist;
@ -193,20 +182,20 @@ namespace verona
t = worklist.back();
worklist.pop_back();
if (t->type().in({Class, Trait}))
if (t->in({Class, Trait}))
{
// Do nothing.
}
else if (t->type().in({Type, TypeIsect}))
else if (t->in({Type, TypeIsect}))
{
// Check that all children are valid for code reuse.
std::for_each(t->node->begin(), t->node->end(), [&](auto& n) {
worklist.push_back(t->make(n));
});
}
else if (t->type() == TypeAlias)
else if (t == TypeAlias)
{
worklist.push_back(t->field(Type));
worklist.push_back(t / Type);
}
else
{
@ -220,7 +209,7 @@ namespace verona
PassDef typevalid()
{
return {
dir::once | dir::topdown,
dir::bottomup | dir::once,
{
T(TypeAlias)[TypeAlias] >> ([](Match& _) -> Node {
if (recursive_typealias(_(TypeAlias)))
@ -245,8 +234,9 @@ namespace verona
}),
In(TypePred)++ * --(In(TypeSubtype, TypeArgs)++) *
(TypeCaps / T(FQType) / T(Trait) / T(TypeTuple) / T(Self) /
T(TypeList) / T(TypeView) / T(TypeVar) / T(Package))[Type] >>
(TypeCaps /
T(Trait, TypeTuple, Self, TypeList, TypeView, TypeVar, Package))
[Type] >>
[](Match& _) {
return err(_(Type), "Can't put this in a type predicate");
},
@ -260,9 +250,17 @@ namespace verona
}),
In(Inherit)++ * --(In(TypeArgs)++) *
(TypeCaps / T(TypeTuple) / T(Self) / T(TypeList) / T(TypeView) /
T(TypeUnion) / T(TypeVar) / T(Package) / T(TypeSubtype) /
T(TypeTrue) / T(TypeFalse))[Type] >>
(TypeCaps /
T(TypeTuple,
Self,
TypeList,
TypeView,
TypeUnion,
TypeVar,
Package,
TypeSubtype,
TypeTrue,
TypeFalse))[Type] >>
[](Match& _) { return err(_(Type), "Can't inherit from this type"); },
}};
}

Просмотреть файл

@ -10,7 +10,7 @@ namespace verona
return {
dir::bottomup | dir::once,
{
(T(FQType) / T(FQFunction))[Type] >> ([](Match& _) -> Node {
T(FQType, FQFunction)[Type] >> ([](Match& _) -> Node {
auto tn = _(Type);
if (is_implicit(tn))
@ -21,10 +21,10 @@ namespace verona
// Ignore TypeParams and TypeTraits, as they don't have predicates.
// If this fails to resolve to a definition, ignore it. It's either
// test code, or the LHS has an error.
if (!bt->type().in({Class, TypeAlias, Function}))
if (!bt->in({Class, TypeAlias, Function}))
return NoChange;
if (!subtype(make_btype(TypeTrue), bt->field(TypePred)))
if (!subtype(make_btype(TypeTrue), bt / TypePred))
return err(tn, "Invalid type arguments");
return NoChange;

Просмотреть файл

@ -1,12 +1,20 @@
# To Do
- Lookup in a `TypeParam`, e.g., `create` or an associated type.
- Blocks.
- Enforce `Return | Move | LLVM` at the end?
- Type inference.
- Uses of `typevar`:
- Return type of `new`, auto-create, lambda create, lambda apply, partial functions, partial app class create, partial app class apply.
- Lambda free variable types.
- `DontCare` syntactically in a type (remove this?).
- Unspecified field types, parameter types, function return types.
- Free variables in object literals.
- Tuples as traits.
- Pattern matching.
- Type inference.
- Type lists.
- `lazy[T]`
- `weak[T]`
- Lookup in a `TypeParam`, e.g., `create` or an associated type.
- Public/private.
- Package schemes.
- Better system for including parts of `std`.
@ -26,78 +34,79 @@ Use `where` for conditional compilation:
## Tuples as Traits
Tuples are traits:
Tuples as traits:
```ts
type Tuple[T, U] =
{
head(self): self.T
rest(self): self.U
}
// make unit a 0-arity tuple
class Unit: Tuple[(), ()]
{
head(self): () = ()
rest(self): () = ()
}
Unit: Tuple[Unit, Unit]
T1: Tuple[T1, Unit]
(T1, T2): Tuple[T1, Tuple[T2, Unit]]
(T1, T2, T3): Tuple[T1, Tuple[T2, Tuple[T3, Unit]]]
(T1, T2, T3, T4): Tuple[T1, Tuple[T2, Tuple[T3, Tuple[T4, Unit]]]]
match w
{
// matches Unit
{ () => e0 }
// matches {} (x = w)
{ x => e1 }
// matches tuple_1 (x = w._0, y = w._1plus)
// problem: for w: (T1, T2), we want y: T2, not y: Tuple[T2, Unit]
{ x, y => e2 }
// matches tuple_2 (x = _0, y = _1, z = _2plus)
{ x, y, z => e3 }
// explicity indicate a w._1plus match?
{ x, y... => e2plus }
{ () => e }
// matches Any (x = w)
{ x => e }
// matches tuple_2 (x = w._0, y = w._1)
{ x, y => e }
// matches tuple_3 (x = w._0, y = w._1, z = w._3)
{ x, y, z => e }
// explicity indicate a tuple_1+ match
// x = w._0, y = w._1plus
{ x, y... => e }
}
x, y... = e // e must be tuple_1
x, y = e // e must be tuple_2
x, y, z... = e // e must be tuple_2
x, y, z = e // e must be tuple_3
// experiment: tuple types
class tuple_1[T1]
class unit
{
_0(self): unit = self
_1plus(self): unit = self
}
type ituple_1 =
{
size(self): Size = 1
apply(self, n: Size): T1 | Unit = if (n == 0) { self._0 }
_0(self): T1
apply(self, n: Size): Self | () = if (n == 0) { self }
_0(self): Self = self
_1plus(self): ()
}
class tuple_2[T1, T2]
type ituple_2[T1, T2] =
{
let _0: T1
let _1: T2
size(self): Size = 2
apply(self, n: Size): T1 | T2 | Unit =
apply(self, n: Size): T1 | T2 | () =
if (n == 0) { self._0 }
else if (n == 1) { self._1 }
_0(self): T1
_1(self): T2
_1plus(self): (T2, ())
_2plus(self): ()
}
class tuple_3[T1, T2, T3]
class tuple_2[T1, T2]: ituple[T1, T2] {}
type ituple_3[T1, T2, T3] =
{
size(self): Size = 2
apply(self, n: Size): T1 | T2 | T3 | Unit =
let _0: T1
let _1: T2
let _2: T3
size(self): Size = 3
apply(self, n: Size): T1 | T2 | T3 | () =
if (n == 0) { self._0 }
else if (n == 1) { self._1 }
else if (n == 2) { self._2 }
_0(self): T1
_1(self): T2
_2(self): T3
_1plus(self): (T2, T3, ())
_2plus(self): (T3, ())
_3plus(self): ()
}
class tuple_3[T1, T2, T3]: ituple[T1, T2, T3] {}
type typelist[T] =
{
size(self): Size
apply(self, n: Size): T | Unit
apply(self, n: Size): T | ()
rest(self, n: Size): typelist[T]
}
```

Просмотреть файл

@ -6,6 +6,27 @@
namespace verona
{
void merge(Bounds& lhs, Bounds& rhs)
{
for (auto& [k, v] : rhs)
{
auto it = lhs.find(k);
if (it == lhs.end())
{
lhs[k] = v;
}
else
{
// TODO: subsume bounds?
it->second.lower.insert(
it->second.lower.end(), v.lower.begin(), v.lower.end());
it->second.upper.insert(
it->second.upper.end(), v.upper.begin(), v.upper.end());
}
}
}
struct Assume
{
Btype sub;
@ -13,8 +34,8 @@ namespace verona
Assume(Btype sub, Btype sup) : sub(sub), sup(sup)
{
assert(sub->type().in({Class, Trait}));
assert(sup->type() == Trait);
assert(sub->in({Class, Trait}));
assert(sup == Trait);
}
};
@ -27,6 +48,7 @@ namespace verona
Btypes self;
Btypes predicates;
std::vector<Assume> assumptions;
Bounds bounds;
Sequent() = default;
@ -37,7 +59,8 @@ namespace verona
rhs_atomic(rhs.rhs_atomic),
self(rhs.self),
predicates(rhs.predicates),
assumptions(rhs.assumptions)
assumptions(rhs.assumptions),
bounds(rhs.bounds)
{}
void push_assume(Btype sub, Btype sup)
@ -52,7 +75,7 @@ namespace verona
void push_self(Btype s)
{
assert(s->type() == Class);
assert(s == Class);
self.push_back(s);
}
@ -67,7 +90,7 @@ namespace verona
while (p)
{
if (p->type().in({Function, Class, TypeAlias}))
if (p->in({Function, Class, TypeAlias}))
{
auto pred = p / TypePred;
@ -81,6 +104,8 @@ namespace verona
bool reduce(Btype l, Btype r)
{
// Start a fresh reduction, keeping the existing Self binding, predicates,
// and assumptions.
Sequent seq;
seq.lhs_pending.push_back(l);
seq.rhs_pending.push_back(r);
@ -89,7 +114,36 @@ namespace verona
seq.assumptions = assumptions;
seq.add_predicates(l);
seq.add_predicates(r);
return seq.reduce();
if (!seq.reduce())
return false;
merge(bounds, seq.bounds);
return true;
}
bool lhs_reduce(Btype t)
{
Sequent seq(*this);
seq.lhs_pending.push_back(t);
if (!seq.reduce())
return false;
merge(bounds, seq.bounds);
return true;
}
bool rhs_reduce(Btype t)
{
Sequent seq(*this);
seq.rhs_pending.push_back(t);
if (!seq.reduce())
return false;
merge(bounds, seq.bounds);
return true;
}
bool reduce()
@ -99,7 +153,7 @@ namespace verona
auto r = rhs_pending.back();
rhs_pending.pop_back();
if (r->type() == TypeUnion)
if (r == TypeUnion)
{
// Π ⊩ Γ ⊢ Δ, A, B
// ---
@ -109,7 +163,7 @@ namespace verona
for (auto& t : *r->node)
rhs_pending.push_back(r->make(t));
}
else if (r->type() == TypeIsect)
else if (r == TypeIsect)
{
// Π ⊩ Γ ⊢ Δ, A
// Π ⊩ Γ ⊢ Δ, B
@ -119,29 +173,23 @@ namespace verona
// RHS isect is a sequent split.
for (auto& t : *r->node)
{
Sequent seq(*this);
seq.rhs_pending.push_back(r->make(t));
if (!seq.reduce())
if (!rhs_reduce(r->make(t)))
return false;
}
return true;
}
else if (r->type() == TypeAlias)
else if (r == TypeAlias)
{
// Demand that we satisfy the type predicate, which is a split.
Sequent seq(*this);
seq.rhs_pending.push_back(r->field(TypePred));
if (!seq.reduce())
if (!rhs_reduce(r / TypePred))
return false;
// Try both the typealias and the underlying type.
rhs_pending.push_back(r->field(Type));
rhs_pending.push_back(r / Type);
rhs_atomic.push_back(r);
}
else if (r->type() == TypeView)
else if (r == TypeView)
{
auto [rr, done] = reduce_view(r);
@ -150,7 +198,7 @@ namespace verona
else
rhs_pending.push_back(rr);
}
else if (r->type() == Self)
else if (r == Self)
{
// Try both Self and the current self type.
rhs_atomic.push_back(r);
@ -169,7 +217,7 @@ namespace verona
auto l = lhs_pending.back();
lhs_pending.pop_back();
if (l->type() == TypeSubtype)
if (l == TypeSubtype)
{
// Π, A < B ⊩ Γ ⊢ Δ, A
// Π, A < B ⊩ Γ, B ⊢ Δ
@ -177,15 +225,12 @@ namespace verona
// Π ⊩ Γ, A < B ⊢ Δ
predicates.push_back(l);
Sequent seq(*this);
seq.rhs_pending.push_back(l->field(Lhs));
if (!seq.reduce())
if (!rhs_reduce(l / Lhs))
return false;
lhs_pending.push_back(l->field(Rhs));
lhs_pending.push_back(l / Rhs);
}
else if (l->type() == TypeIsect)
else if (l == TypeIsect)
{
// Γ, A, B ⊢ Δ
// ---
@ -195,7 +240,7 @@ namespace verona
for (auto& t : *l->node)
lhs_pending.push_back(l->make(t));
}
else if (l->type() == TypeUnion)
else if (l == TypeUnion)
{
// Γ, A ⊢ Δ
// Γ, B ⊢ Δ
@ -205,25 +250,22 @@ namespace verona
// LHS union is a sequent split.
for (auto& t : *l->node)
{
Sequent seq(*this);
seq.lhs_pending.push_back(l->make(t));
if (!seq.reduce())
if (!lhs_reduce(l->make(t)))
return false;
}
return true;
}
else if (l->type() == TypeAlias)
else if (l == TypeAlias)
{
// Assume that we've satisfied the type predicate.
lhs_pending.push_back(l->field(TypePred));
lhs_pending.push_back(l / TypePred);
// Try both the typealias and the underlying type.
lhs_pending.push_back(l->field(Type));
lhs_pending.push_back(l / Type);
lhs_atomic.push_back(l);
}
else if (l->type() == TypeView)
else if (l == TypeView)
{
auto [ll, done] = reduce_view(l);
@ -232,7 +274,7 @@ namespace verona
else
rhs_pending.push_back(ll);
}
else if (l->type() == Self)
else if (l == Self)
{
// Try both Self and the current self type.
lhs_atomic.push_back(l);
@ -273,27 +315,27 @@ namespace verona
bool subtype_one(Btype& l, Btype& r)
{
// TypeFalse is a subtype of everything.
if (l->type() == TypeFalse)
if (l == TypeFalse)
return true;
// Everything is a subtype of TypeTrue.
if (r->type() == TypeTrue)
if (r == TypeTrue)
return true;
// Skip TypeVar on either side.
if ((l->type() == TypeVar) || (r->type() == TypeVar))
if ((l == TypeVar) || (r == TypeVar))
return false;
// These must be the same type.
// TODO: region tracking
if (r->type().in({Iso, Mut, Imm, Self}))
if (r->in({Iso, Mut, Imm, Self}))
return l->type() == r->type();
// Tuples must be the same arity and each element must be a subtype.
// TODO: remove TypeTuple from the language, use a trait
if (r->type() == TypeTuple)
if (r == TypeTuple)
{
return (l->type() == TypeTuple) &&
return (l == TypeTuple) &&
std::equal(
l->node->begin(),
l->node->end(),
@ -307,43 +349,49 @@ namespace verona
// Nothing is a subtype of a TypeList. Two TypeLists may have
// different instantiated arity, even if they have the same bounds.
// Use a TypeParam with a TypeList upper bounds to get subtyping.
if (r->type() == TypeList)
if (r == TypeList)
return false;
// Check for the same definition site.
if (r->type() == TypeParam)
if (r == TypeParam)
return same_def_site(l, r);
// Check for the same definition site with invariant typeargs.
if (r->type().in({TypeAlias, Class}))
if (r->in({TypeAlias, Class}))
return same_def_site(l, r) && invariant_typeargs(l, r);
// A package resolves to a class. Once we have package resolution,
// compare the classes, as different strings could resolve to the
// same package.
if (r->type() == Package)
if (r == Package)
{
return (l->type() == Package) &&
return (l == Package) &&
((l->node / Ident)->location() == (r->node / Ident)->location());
}
// Check predicate subtyping.
if (r->type() == TypeSubtype)
if (r == TypeSubtype)
{
// ⊩ Π, A ⊢ B
// ---
// Π ⊩ Γ ⊢ Δ, A < B
Sequent seq;
seq.lhs_pending = predicates;
seq.lhs_pending.push_back(r->field(Lhs));
seq.rhs_pending.push_back(r->field(Rhs));
return seq.reduce();
seq.lhs_pending.push_back(r / Lhs);
seq.rhs_pending.push_back(r / Rhs);
seq.bounds = bounds;
if (!seq.reduce())
return false;
merge(bounds, seq.bounds);
return true;
}
// Check structural subtyping.
if (r->type() == Trait)
if (r == Trait)
{
if (!l->type().in({Class, Trait}))
if (!l->in({Class, Trait}))
return false;
// If any assumption is true, the trait is satisfied.
@ -361,7 +409,7 @@ namespace verona
push_assume(l, r);
if (l->type() == Class)
if (l == Class)
push_self(l);
bool ok = true;
@ -369,7 +417,7 @@ namespace verona
for (auto rf : *rbody)
{
if (rf->type() != Function)
if (rf != Function)
continue;
// At this point, traits have been decomposed into intersections of
@ -377,11 +425,9 @@ namespace verona
auto id = (rf / Ident)->location();
auto arity = (rf / Params)->size();
auto lfs = l->node->lookdown(id);
auto it = std::find_if(
lfs.begin(), lfs.end(), [&](auto& lf) {
return (lf->type() == Function) &&
((lf / Params)->size() == arity);
});
auto it = std::find_if(lfs.begin(), lfs.end(), [&](auto& lf) {
return (lf == Function) && ((lf / Params)->size() == arity);
});
if (it == lfs.end())
{
@ -433,14 +479,14 @@ namespace verona
// TODO: If the check succeeded, memoize it.
pop_assume();
if (l->type() == Class)
if (l == Class)
pop_self();
return ok;
}
// TODO: handle viewpoint adaptation
if (r->type() == TypeView)
if (r == TypeView)
{
// TODO: the end of a TypeView can be a TypeParam. If it is, we need to
// be able to use that to fulfill Class / Trait / etc if the TypeView is
@ -456,15 +502,17 @@ namespace verona
{
bool ok = false;
if (l->type() == TypeVar)
if (l == TypeVar)
{
// TODO: l.upper += r
bounds[l->node->location()].upper.push_back(r);
ok = true;
}
if (r->type() == TypeVar)
if (r == TypeVar)
{
// TODO: r.lower += l
bounds[r->node->location()].lower.push_back(l);
ok = true;
}
@ -484,7 +532,7 @@ namespace verona
while (node)
{
if (node->type().in({Class, TypeAlias, Function}))
if (node->in({Class, TypeAlias, Function}))
{
for (auto& tp : *(node / TypeParams))
{
@ -504,7 +552,7 @@ namespace verona
std::pair<Btype, bool> reduce_view(Btype& t)
{
assert(t->type() == TypeView);
assert(t == TypeView);
auto start = t->node->begin();
auto end = t->node->end();
@ -514,8 +562,7 @@ namespace verona
auto rhs = NodeRange{it + 1, end};
auto r = t->make(*it);
if (r->type().in(
{Package, Class, Trait, TypeTuple, TypeTrue, TypeFalse}))
if (r->in({Package, Class, Trait, TypeTuple, TypeTrue, TypeFalse}))
{
// The viewpoint path can be discarded.
if (*it == t->node->back())
@ -524,7 +571,7 @@ namespace verona
// There is no view through this type, so treat it as true, i.e. top.
return {t->make(TypeTrue), false};
}
else if (r->type() == TypeList)
else if (r == TypeList)
{
// A.(B...) = (A.B)...
if (*it == t->node->back())
@ -535,7 +582,7 @@ namespace verona
// There is no view through this type, so treat it as true, i.e. top.
return {t->make(TypeTrue), false};
}
else if (r->type().in({TypeUnion, TypeIsect}))
else if (r->in({TypeUnion, TypeIsect}))
{
// A.(B | C).D = A.B.D | A.C.D
// A.(B & C).D = A.B.D & A.C.D
@ -546,12 +593,12 @@ namespace verona
return {r->make(node), false};
}
else if (r->type() == TypeAlias)
else if (r == TypeAlias)
{
return {
r->field(Type)->make(TypeView << -lhs << -r->node << -rhs), false};
(r / Type)->make(TypeView << -lhs << -r->node << -rhs), false};
}
else if (r->type() == TypeView)
else if (r == TypeView)
{
// A.(B.C).D = A.B.C.D
auto node = TypeView << -lhs;
@ -572,6 +619,7 @@ namespace verona
auto r = t->make(*it);
// If any step in the view is Imm, the whole view is Imm.
// TODO: if r is a TypeVar, this will bind it to `imm` and succeed.
if (reduce(r, t_imm))
{
if (*it == t->node->back())
@ -586,15 +634,28 @@ namespace verona
}
};
bool subtype(Node sub, Node sup)
{
Sequent seq;
return seq.reduce(make_btype(sub), make_btype(sup));
}
bool subtype(Btype sub, Btype sup)
{
Sequent seq;
return seq.reduce(sub, sup);
seq.lhs_pending.push_back(sub);
seq.rhs_pending.push_back(sup);
seq.add_predicates(sub);
seq.add_predicates(sub);
return seq.reduce();
}
bool subtype(Btype sub, Btype sup, Bounds& bounds)
{
Sequent seq;
seq.lhs_pending.push_back(sub);
seq.rhs_pending.push_back(sup);
seq.add_predicates(sub);
seq.add_predicates(sub);
if (!seq.reduce())
return false;
merge(bounds, seq.bounds);
return true;
}
}

Просмотреть файл

@ -12,6 +12,14 @@ namespace verona
{
using namespace trieste;
bool subtype(Node sub, Node sup);
struct Bound
{
std::vector<Btype> lower;
std::vector<Btype> upper;
};
using Bounds = std::map<Location, Bound>;
bool subtype(Btype sub, Btype sup);
bool subtype(Btype sub, Btype sup, Bounds& bounds);
}

176
src/wf.h
Просмотреть файл

@ -8,14 +8,14 @@ namespace verona
{
using namespace wf::ops;
inline const auto wfImplicit = Implicit >>= Implicit | Explicit;
inline const auto wfImplicit = Implicit >>= Implicit | Explicit | LambdaFunc;
inline const auto wfHand = Ref >>= Lhs | Rhs;
inline const auto wfParserTokens = Bool | Int | Hex | Bin | Float | HexFloat |
Char | Escaped | String | LLVM | Iso | Mut | Imm | Brace | Paren | Square |
List | Equals | Arrow | Use | Class | TypeAlias | Where | Var | Let | Ref |
Self | If | Else | New | Try | DontCare | Ident | Ellipsis | Dot | Colon |
DoubleColon | TripleColon | Symbol;
inline const auto wfParserTokens = True | False | Int | Hex | Oct | Bin |
Float | HexFloat | Char | Escaped | String | LLVM | Iso | Mut | Imm |
Brace | Paren | Square | List | Equals | Arrow | Use | Class | TypeAlias |
Where | Var | Let | Ref | Self | If | Else | New | Try | DontCare | Ident |
Ellipsis | Dot | Colon | DoubleColon | TripleColon | Symbol;
// clang-format off
inline const auto wfParser =
@ -56,11 +56,12 @@ namespace verona
Ellipsis | Ident | Symbol | Dot | DoubleColon;
inline const auto wfExprStructure = Expr | ExprSeq | Unit | Tuple | Assign |
TypeArgs | If | Else | Lambda | Let | Var | New | Try | Ref | DontCare |
Ellipsis | Dot | Ident | Symbol | DoubleColon | Bool | Int | Hex | Bin |
Float | HexFloat | Char | Escaped | String | LLVM | TypeAssert;
TypeArgs | Self | If | Else | Lambda | Let | Var | New | Try | Ref |
DontCare | Ellipsis | Dot | Ident | Symbol | DoubleColon | True | False |
Int | Hex | Oct | Bin | Float | HexFloat | Char | Escaped | String | LLVM |
TypeAssert;
inline const auto wfDefault = Default >>= Lambda | DontCare;
inline const auto wfDefault = Default >>= Block | DontCare;
// clang-format off
inline const auto wfPassStructure =
@ -102,13 +103,60 @@ namespace verona
;
// clang-format on
// Add RefVar, RefLet, Selector, FQFunction.
inline const auto wfExprReference =
wfExprStructure | RefVar | RefLet | Selector;
// clang-format off
inline const auto wfPassReference =
wfPassStructure
| (RefLet <<= Ident)
| (RefVar <<= Ident)
| (Selector <<= wfHand * Ident * Int * TypeArgs)
| (Expr <<= wfExprReference++[1])
;
// clang-format on
// Remove If, Else. Add Conditional, TypeTest, Cast.
inline const auto wfExprConditionals =
(wfExprReference - (If | Else)) | Conditional | TypeTest | Cast;
// clang-format off
inline const auto wfPassConditionals =
wfPassReference
| (Conditional <<= (If >>= Expr) * Block * Block)
| (TypeTest <<= Expr * Type)
| (Cast <<= Expr * Type)
| (Expr <<= wfExprConditionals++[1])
;
// clang-format on
// Remove Lambda.
inline const auto wfExprLambda = wfExprConditionals - Lambda;
// clang-format off
inline const auto wfPassLambda =
wfPassConditionals
| (Expr <<= wfExprLambda++[1])
;
// clang-format on
// clang-format off
inline const auto wfPassDefaultArgs =
wfPassLambda
| (FieldLet <<= wfImplicit * Ident * Type)[Ident]
| (FieldVar <<= wfImplicit * Ident * Type)[Ident]
| (Param <<= Ident * Type)[Ident]
;
// clang-format on
// Remove DontCare, Ident. Add FQType.
inline const auto wfTypeNames =
(wfTypeStructure - (DontCare | Ident)) | FQType;
// clang-format off
inline const auto wfPassTypeNames =
wfPassStructure
wfPassDefaultArgs
| (FQType <<=
TypePath *
(Type >>=
@ -120,7 +168,6 @@ namespace verona
| (TypeAliasName <<= Ident * TypeArgs)
| (TypeParamName <<= Ident)
| (TypeTraitName <<= Ident)
| (Selector <<= wfHand * Ident * Int * TypeArgs)
| (Type <<= wfTypeNames++)
;
// clang-format on
@ -162,7 +209,7 @@ namespace verona
;
// clang-format on
// Remove Type.
// Remove Type. Types are no longer sequences.
inline const auto wfType = wfTypeAlg - Type;
// clang-format off
@ -174,69 +221,52 @@ namespace verona
| (TypeSubtype <<= (Lhs >>= wfType) * (Rhs >>= wfType))
| (TypeUnion <<= (wfType - TypeUnion)++[2])
| (TypeIsect <<= (wfType - TypeIsect)++[2])
// Types are no longer sequences.
| (Type <<= wfType)
;
// clang-format on
// Remove TypeArgs, New, Ident, Symbol, DoubleColon.
// Add RefVar, RefLet, Selector, FQFunction.
inline const auto wfExprReference =
(wfExprStructure - (TypeArgs | New | Ident | Symbol | DoubleColon)) |
RefVar | RefLet | Selector | FQFunction;
// Remove New, Ident, Symbol, Self, DoubleColon, TypeArgs. Add FQFunction.
inline const auto wfExprTypeReference =
(wfExprLambda - (New | Ident | Symbol | Self | DoubleColon | TypeArgs)) |
FQFunction;
// clang-format off
inline const auto wfPassReference =
inline const auto wfPassTypeReference =
wfPassTypeFlat
| (RefLet <<= Ident)
| (RefVar <<= Ident)
| (FQFunction <<= FQType * Selector)
| (Expr <<= wfExprReference++[1])
| (Expr <<= wfExprTypeReference++[1])
;
// clang-format on
// Remove If, Else. Add Conditional, TypeTest, Cast.
inline const auto wfExprConditionals =
(wfExprReference - (If | Else)) | Conditional | TypeTest | Cast;
// Remove Use. Remove implicit marker on fields.
// clang-format off
inline const auto wfPassConditionals =
wfPassReference
| (Conditional <<= (If >>= Expr) * Block * Block)
| (TypeTest <<= Expr * Type)
| (Cast <<= Expr * Type)
// Remove implicit marker.
| (FieldLet <<= Ident * Type * wfDefault)[Ident]
| (FieldVar <<= Ident * Type * wfDefault)[Ident]
| (Expr <<= wfExprConditionals++[1])
inline const auto wfPassResetImplicit =
wfPassTypeReference
| (ClassBody <<= (Class | TypeAlias | FieldLet | FieldVar | Function)++)
| (Block <<= (Class | TypeAlias | Expr)++[1])
| (FieldLet <<= Ident * Type)[Ident]
| (FieldVar <<= Ident * Type)[Ident]
;
// clang-format on
// Remove Dot. Add Call, NLRCheck.
inline const auto wfExprReverseApp =
(wfExprConditionals - Dot) | Call | NLRCheck;
(wfExprTypeReference - Dot) | Call | NLRCheck;
// clang-format off
inline const auto wfPassReverseApp =
wfPassConditionals
// Remove Use.
| (ClassBody <<= (Class | TypeAlias | FieldLet | FieldVar | Function)++)
| (Block <<= (Class | TypeAlias | Expr)++[1])
wfPassResetImplicit
| (Call <<= (Selector >>= (Selector | FQFunction)) * Args)
| (Args <<= Expr++)
| (NLRCheck <<= wfImplicit * Call)
| (NLRCheck <<= Call)
| (Expr <<= wfExprReverseApp++[1])
;
// clang-format on
// Remove Unit, DontCare, Ellipsis, Selector, FQFunction.
// Remove Unit, True, False, DontCare, Ellipsis, Selector, FQFunction.
// Add RefVarLHS.
inline const auto wfExprApplication =
(wfExprReverseApp - (Unit | DontCare | Ellipsis | Selector | FQFunction)) |
(wfExprReverseApp -
(Unit | True | False | DontCare | Ellipsis | Selector | FQFunction)) |
RefVarLHS;
// clang-format off
@ -274,63 +304,34 @@ namespace verona
// clang-format on
// Remove Assign, Let, TupleLHS. Add Bind.
inline const auto wfExprBind =
inline const auto wfExprAssignment =
(wfExprAssign - (Assign | Let | TupleLHS)) | Bind;
// clang-format off
inline const auto wfPassAssignment =
wfPassLocalVar
| (Bind <<= Ident * Type * Expr)[Ident]
| (Expr <<= wfExprBind)
;
// clang-format on
// Remove Lambda.
inline const auto wfExprLambda = wfExprBind - Lambda;
inline const auto wfNLRDefault = Default >>= NLRCheck | DontCare;
// clang-format off
inline const auto wfPassLambda =
wfPassAssignment
| (FieldLet <<= Ident * Type * wfNLRDefault)[Ident]
| (FieldVar <<= Ident * Type * wfNLRDefault)[Ident]
| (Param <<= Ident * Type * wfNLRDefault)[Ident]
| (Expr <<= wfExprLambda)
| (Expr <<= wfExprAssignment)
;
// clang-format on
// Add FieldRef.
inline const auto wfExprAutoFields = wfExprLambda | FieldRef;
inline const auto wfExprAutoFields = wfExprAssignment | FieldRef;
// clang-format off
inline const auto wfPassAutoFields =
wfPassLambda
wfPassAssignment
| (FieldRef <<= RefLet * Ident)
| (Expr <<= wfExprAutoFields)
;
// clang-format on
// clang-format off
inline const auto wfPassAutoCreate =
wfPassAutoFields
| (FieldLet <<= Ident * Type)[Ident]
| (FieldVar <<= Ident * Type)[Ident]
;
// clang-format on
// clang-format off
inline const auto wfPassDefaultArgs =
wfPassAutoCreate
| (Param <<= Ident * Type)[Ident]
;
// clang-format on
// Remove NLRCheck.
inline const auto wfExprNLRCheck = wfExprAutoFields - NLRCheck;
// clang-format off
inline const auto wfPassNLRCheck =
wfPassDefaultArgs
wfPassAutoFields
// Add Return.
| (Block <<= (Class | TypeAlias | Expr | Return)++[1])
@ -357,8 +358,8 @@ namespace verona
;
// clang-format on
// Remove RefLet. Add Copy, Move, Drop.
inline const auto wfExprDrop = (wfExprANF - RefLet) | Copy | Move | Drop;
// Remove RefLet. Add Copy, Move.
inline const auto wfExprDrop = (wfExprANF - RefLet) | Copy | Move;
// clang-format off
inline const auto wfPassDrop =
@ -368,11 +369,12 @@ namespace verona
| (Drop <<= Ident)
| (Block <<=
(Class | TypeAlias | Bind | Return | LLVM | Move | Drop)++[1])
| (Return <<= Move)
| (Return <<= (Ref >>= Move))
| (Tuple <<= (TupleFlatten | Copy | Move)++[2])
| (TupleFlatten <<= Copy | Move)
| (Args <<= (Copy | Move)++)
| (Conditional <<= (If >>= Copy | Move) * Block * Block)
| (Conditional <<=
(If >>= Copy | Move) * (True >>= Block) * (False >>= Block))
| (TypeTest <<= (Ref >>= (Copy | Move)) * Type)
| (Cast <<= (Ref >>= (Copy | Move)) * Type)
| (FieldRef <<= (Ref >>= (Copy | Move)) * Ident)

Просмотреть файл

@ -11,6 +11,18 @@ class Bool
from.bool()
}
make_true(): Bool
{
let a = :[i1 1]:
Dyn::from_bool(a)
}
make_false(): Bool
{
let a = :[i1 0]:
Dyn::from_bool(a)
}
bool(self: Bool): Bool
{
self