Skip to content

Commit

Permalink
revert parsing 'fix' that broke shit, wrote long-ass comment
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiayang committed Mar 23, 2019
1 parent 9e56a77 commit 2ba6f1e
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 35 deletions.
28 changes: 15 additions & 13 deletions build/supertiny.flx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

export supertiny

import libc as _
// import libc as _
import libc

// import std::io
// import std::map
Expand All @@ -28,18 +29,19 @@ struct foo

@entry fn main()
{
do {
var addr: ipv4
// addr.raw = -16668480;
addr.raw = 0xff01a8c0;

printf("%d.%d.%d.%d\n", addr._.bytes[0], addr._.bytes[1], addr._.bytes[2], addr._.bytes[3]);

// addr._.bytes[0] = 192
// addr._.bytes[1] = 168
// addr._.bytes[2] = 1
// addr._.bytes[3] = 1
}
libc::printf("hello world %d\n", 1)
// do {
// var addr: ipv4
// // addr.raw = -16668480;
// addr.raw = 0xff01a8c0;

// printf("%d.%d.%d.%d\n", addr._.bytes[0], addr._.bytes[1], addr._.bytes[2], addr._.bytes[3]);

// // addr._.bytes[0] = 192
// // addr._.bytes[1] = 168
// // addr._.bytes[2] = 1
// // addr._.bytes[3] = 1
// }


/* do {
Expand Down
9 changes: 6 additions & 3 deletions source/codegen/call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,13 @@ CGResult sst::ExprCall::_codegen(cgn::CodegenState* cs, fir::Type* infer)

auto ft = fn->getType()->toFunctionType();

if(ft->getArgumentTypes().size() != this->arguments.size() && !ft->isVariadicFunc())
if(ft->getArgumentTypes().size() != this->arguments.size())
{
error(this, "Mismatched number of arguments; expected %zu, but %zu were given",
ft->getArgumentTypes().size(), this->arguments.size());
if((!ft->isVariadicFunc() && !ft->isCStyleVarArg()) || this->arguments.size() < ft->getArgumentTypes().size())
{
error(this, "Mismatched number of arguments; expected %zu, but %zu were given",
ft->getArgumentTypes().size(), this->arguments.size());
}
}

std::vector<FnCallArgument> fcas = util::map(this->arguments, [](sst::Expr* arg) -> FnCallArgument {
Expand Down
66 changes: 63 additions & 3 deletions source/frontend/parser/expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,71 @@ namespace parser
{
switch(t)
{
case TT::DoubleColon:
return 5000;
/*
! ACHTUNG !
* DOCUMENT THIS SOMEWHERE PROPERLY!!! *
due to how we handle identifiers and scope paths (foo::bar), function calls must have higher precedence
than scope resolution.
this might seem counter-intuitive (i should be resolving the complete identifier first, then calling it with
()! why would it be any other way???), this is a sad fact of how the typechecker works.
as it stands, identifiers are units; paths consist of multiple identifiers in a DotOp with the :: operator, which
is left-associative. so for something like foo::bar::qux, it's ((foo)::(bar))::qux.
to resolve a function call, eg. foo::bar::qux(), the DotOp is laid out as [foo::bar]::[qux()] (with [] for grouping),
instead of the 'intuitive' [[foo::bar]::qux](). the reason for this design was the original rewrite goal of not
relying on string manipulation in the compiler; having identifiers contain :: would have been counter to that
goal.
(note: currently we are forced to manipulate ::s in the pts->fir type converter!!)
the current typechecker will thus first find a namespace 'foo', and within that a namespace 'bar', and within that
a function 'qux'. this is opposed to finding a namespace 'foo', then 'bar', then an identifier 'qux', and leaving
that to be resolved later.
also, another potential issue is how we deal with references to functions (ie. function pointers). our resolver
for ExprCall is strictly less advanced than that for a normal FunctionCall (for reasons i can't reCALL (lmao)), so
we would prefer to return a FuncCall rather than an ExprCall.
this model could be re-architected without a *major* rewrite, but it would be a non-trivial task and a considerable amount
of work and debugging. for reference:
1. make Idents be able to refer to entire paths; just a datastructure change
2. make :: have higher precedence than (), to take advantage of (1)
3. parse ExprCall and FuncCall identically -- they should both just be a NewCall, with an Expr as the callee
4. in typechecking a NewCall, just call ->typecheck() on the LHS; the current implementation of Ident::typecheck
returns an sst::VarRef, which has an sst::VarDefn field which we can use.
4a. if the Defn was a VarDefn, they cannot overload, and we can just do what we currently do for ExprCall.
if it was a function defn, then things get more complicated.
5. the Defn was a FuncDefn. currently Ident cannot return more than one Defn in the event of ambiguous results (eg.
when overloading!), which means we are unable to properly do overload resolution! (duh) we need to make a mechanism
for Ident to return a list of Defns.
potential solution (A): make an sst::AmbiguousDefn struct that itself holds a list of Defns. the VarRef returned by
Ident would then return that in the ->def field. this would only happen when the target is function; i presume we
have existing mechanisms to detect invalid "overload" scenarios.
back to (4), we should in theory be able to resolve functions from a list of defns.
the problem with this is that while it might seem like a simple 5.5-step plan, a lot of the supporting resolver functions
need to change, and effort is better spent elsewhere tbh
for now we just stick to parsing () at higher precedence than ::.
*/


case TT::LParen:
return 2000;
return 9001; // very funny

case TT::DoubleColon:
return 5000;

case TT::Period:
return 1500;
Expand Down
4 changes: 2 additions & 2 deletions source/typecheck/call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ sst::Expr* ast::ExprCall::typecheckWithArguments(sst::TypecheckState* fs, const
iceAssert(target);

if(!target->type->isFunctionType())
error(this->callee, "expression with non-function-type '%s' cannot be called");
error(this->callee, "expression with non-function-type '%s' cannot be called", target->type);

auto ft = target->type->toFunctionType();
auto [ dist, errs ] = sst::resolver::computeOverloadDistance(this->loc, util::map(ft->getArgumentTypes(), [](fir::Type* t) -> auto {
return fir::LocatedType(t, Location());
}), util::map(arguments, [](const FnCallArgument& fca) -> fir::LocatedType {
return fir::LocatedType(fca.value->type, fca.loc);
}), false);
}), target->type->toFunctionType()->isCStyleVarArg());

if(errs != nullptr || dist == -1)
{
Expand Down
38 changes: 24 additions & 14 deletions source/typecheck/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,37 @@ TCResult ast::LitNumber::typecheck(sst::TypecheckState* fs, fir::Type* infer)
bool sgn = mpfr::signbit(number);
bool flt = !mpfr::isint(number);

//* this is the stupidest thing.

// mpfr's 'get_min_prec' returns the number of bits required to store the significand (eg. for 1.413x10^-2, it is 1.413).
// so you'd think that, for example, given '1024', it would return '10', given that 2^10 == 1024.
// no, it returns '1', because you only need one bit -- the 10th bit -- to get the value 1024.
// which is fucking stupid.
size_t bits = 0;
if(flt)
{
// fuck it lah.
bits = sizeof(double) * CHAR_BIT;
}
else
{
auto m_ptr = number.mpfr_ptr();
auto m_rnd = MPFR_RNDN;
if(mpfr_fits_sshort_p(m_ptr, m_rnd))
bits = sizeof(short) * CHAR_BIT;

// so what we do here is we change the last digit of the number to be '9'. this effectively forces the first
// bit of the entire number to be set (we don't use '1' because we don't want to make the number smaller
// -- eg. 1024 would become 1021, which would only need 9 bits to store -- versus 1029)
else if(mpfr_fits_sint_p(m_ptr, m_rnd))
bits = sizeof(int) * CHAR_BIT;

// in this way we force mpfr to return the real number of bits required to store the entire thing properly.
else if(mpfr_fits_slong_p(m_ptr, m_rnd))
bits = sizeof(long) * CHAR_BIT;

size_t bits = mpfr_min_prec(mpfr::mpreal(this->num.substr(0, this->num.size() - 1) + "9").mpfr_ptr());
else if(mpfr_fits_intmax_p(m_ptr, m_rnd))
bits = sizeof(intmax_t) * CHAR_BIT;

printf("number %s: %d / %d\n", number.toString().c_str(), sgn, bits);
else if(!sgn && mpfr_fits_uintmax_p(m_ptr, m_rnd))
bits = sizeof(uintmax_t) * CHAR_BIT;

printf("bits for %s: %d\n", this->num.c_str(), mpfr_min_prec(mpfr::mpreal(this->num).mpfr_ptr()));
else // lmao
bits = SIZE_MAX;
}

auto ret = util::pool<sst::LiteralNumber>(this->loc, (infer && infer->isPrimitiveType()) ? infer : fir::ConstantNumberType::get(sgn, flt, bits));
ret->num = mpfr::mpreal(this->num);
ret->num = number;

return TCResult(ret);
}
Expand Down

0 comments on commit 2ba6f1e

Please sign in to comment.