From 0ad047fe49bd23af27aa49c9a5237eb084ebc391 Mon Sep 17 00:00:00 2001 From: zhiayang <500236+zhiayang@users.noreply.github.com> Date: Sun, 6 Oct 2019 23:08:45 +0800 Subject: [PATCH 1/4] Update semaphore.yml --- .semaphore/semaphore.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 0f86b225..756bed80 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -24,18 +24,3 @@ blocks: - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile -run -backend llvm build/tester.flx - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile -run -backend interp build/tester.flx - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile build/tester.flx && ./tester - - name: "macos-build" - task: - agent: - machine: - type: a1-standard-4 - os_image: macos-mojave - jobs: - - name: build - commands: - - checkout - - HOMEBREW_NO_INSTALL_CLEANUP=1 brew install llvm@7 mpfr libffi - - PATH="/usr/local/opt/llvm@7/bin:$PATH" LLVM_CONFIG=llvm-config make -j4 build - - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile -run -backend llvm build/tester.flx - - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile -run -backend interp build/tester.flx - - build/sysroot/usr/local/bin/flaxc -sysroot build/sysroot -profile build/tester.flx && ./tester From 461e4ed5ff018c753cc6f0c8c75d1385486261f1 Mon Sep 17 00:00:00 2001 From: zhiayang Date: Tue, 8 Oct 2019 01:29:37 +0800 Subject: [PATCH 2/4] update readme a bit --- README.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 33490e7b..3a04b8ff 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ A low level, general-purpose language with high level syntax and expressibility. I work on Flax in my spare time, and as the lone developer I cannot guarantee continuous development. I'm no famous artist but this is my magnum opus, so it'll not be abandoned anytime soon. -Development is currently on hiatus. Work will resume NET 2019-12-09. +Development is currently on hiatus. Regular work will resume NET 2019-12-09. ### Language Goals @@ -44,19 +44,24 @@ Development is currently on hiatus. Work will resume NET 2019-12-09. ### Current Features -- Structs, classes, unions, enums +- Structs, unions, enums - Arrays (fixed and dynamic), slices - Pointer manipulation/arithmetic - Operator overloading - Generic functions and types - Type inference (including for generics) - Full compile-time execution (of arbitrary code) +- Classes, including virtual dispatch and (single) inheritance ----------------------------------------------- ### Language Syntax -- See https://flax-lang.github.io (incomplete, outdated, obsolete, etc. etc.) + +- We don't have a proper place that documents everything yet, but most of the basic stuff is probably not gonna change much. + The testing code in `build/tests/` (most of them, anyway — check `tester.flx` to see which ones we call) tests basically 90% of the + language, so that's the syntax reference for now. +- Yes, the syntax is not "officially" defined by a grammar. The reference parser implementation is the One True Definition, for now. ----------------------------------------------- @@ -64,6 +69,16 @@ Development is currently on hiatus. Work will resume NET 2019-12-09. ### Code Sample +```rust +import std::io as _ + +@entry fn main() +{ + println("hello, world!") +} + +``` + ```rust do { fn prints(m: T, a: [U: ...]) From 6a974fbc30556e74f3db7144a6f4213e76c43b21 Mon Sep 17 00:00:00 2001 From: zhiayang Date: Fri, 11 Oct 2019 10:39:49 +0800 Subject: [PATCH 3/4] fix lvalue poof when calling method on rvalues --- build/ultratiny.flx | 38 ++++++++++++++++++++++++++++++------ source/codegen/dotop.cpp | 9 +++++++++ source/frontend/errors.cpp | 6 ++++++ source/include/utils.h | 8 +++++++- source/typecheck/classes.cpp | 8 +++----- source/typecheck/dotop.cpp | 3 ++- 6 files changed, 59 insertions(+), 13 deletions(-) diff --git a/build/ultratiny.flx b/build/ultratiny.flx index 268a444e..138e51a0 100644 --- a/build/ultratiny.flx +++ b/build/ultratiny.flx @@ -58,9 +58,10 @@ class Z: Y class A { init() { } - virtual fn foo(a: Y) -> Y + virtual fn lol(a: Y) -> &Y { - return Y(c: 471) + std::io::println("A::foo()") + return alloc Y(c: 471) } } @@ -68,21 +69,46 @@ class B : A { init() : super() { } - override fn foo(a: Y) -> Y + override fn foo(a: Y) -> &Y { - return Y(c: 748) + std::io::println("B::foo()") + return alloc Z(c: 748) + // return 3 } } +// import std::io as _ + +// @entry fn main() +// { +// println("hello, world!") +// } + +// issue #0: we basically don't really even check for overriding methods properly. // issue #1: co/contra-variance of return and parameter types for virtual methods // issue #2: crashes when initialisers have default arguments?? // classes are a Bad Idea (tm) ): +struct Tmp +{ + k: int + m: int + + fn meth() -> int => k * m +} + @entry fn main() { - let a = B() - let q = a.foo(Y(c: 1)).data + // let a = B() + // let q = a.foo(Y(c: 1)).data + + // let y: &X = alloc Y(c: 41) + // std::io::println("y = %", y.data) + + // let q = Tmp(k: 3, m: 7).meth() + + // let q = B().foo(Y(c: 1)).data std::io::println("thing: %", q) } diff --git a/source/codegen/dotop.cpp b/source/codegen/dotop.cpp index 3e8d67de..8f136a16 100644 --- a/source/codegen/dotop.cpp +++ b/source/codegen/dotop.cpp @@ -62,6 +62,15 @@ CGResult sst::MethodDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) fir::Type* sty = 0; auto res = getAppropriateValuePointer(cs, this, this->lhs, &sty); + if(!res->islvalue()) + { + auto tmplval = cs->irb.CreateLValue(this->lhs->type); + cs->irb.Store(res.value, tmplval); + + res.value = tmplval; + res->makeConst(); + } + // then we insert it as the first argument auto rv = util::pool(this->loc, res.value->getType()->getMutablePointerTo()); rv->rawValue = CGResult(cs->irb.AddressOf(res.value, true)); diff --git a/source/frontend/errors.cpp b/source/frontend/errors.cpp index de96e8c1..050c7a67 100644 --- a/source/frontend/errors.cpp +++ b/source/frontend/errors.cpp @@ -467,6 +467,7 @@ void OverloadError::post() + [[noreturn]] void doTheExit(bool trace) { fprintf(stderr, "there were errors, compilation cannot continue\n"); @@ -487,3 +488,8 @@ void OverloadError::post() + + + + + diff --git a/source/include/utils.h b/source/include/utils.h index 7f39a6b2..d265a6a8 100644 --- a/source/include/utils.h +++ b/source/include/utils.h @@ -171,7 +171,13 @@ namespace util template std::vector take(const std::vector& v, size_t num) { - return std::vector(v.begin(), v.begin() + num); + return std::vector(v.begin(), v.begin() + std::min(num, v.size())); + } + + template + std::vector drop(const std::vector& v, size_t num) + { + return std::vector(v.begin() + std::min(num, v.size()), v.end()); } inline std::string join(const std::vector& list, const std::string& sep) diff --git a/source/typecheck/classes.cpp b/source/typecheck/classes.cpp index 5a0c108a..48752a45 100644 --- a/source/typecheck/classes.cpp +++ b/source/typecheck/classes.cpp @@ -209,13 +209,11 @@ TCResult ast::ClassDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, co { // ok -- issue is that we cannot compare the method signatures directly -- because the method will take the 'self' of its // respective class, meaning they won't be duplicates. so, we must compare without the first parameter. - - // note: we're passing by copy here intentionally so we can erase the first one. - auto compareMethods = [&fs](std::vector a, std::vector b) -> bool { - return fs->isDuplicateOverload(a, b); + auto compareMethodSignatures = [&fs](const std::vector& a, const std::vector& b) -> bool { + return fs->isDuplicateOverload(util::drop(a, 1), util::drop(b, 1)); }; - if(bf->id.name == meth->id.name && compareMethods(bf->params, meth->params)) + if(bf->id.name == meth->id.name && compareMethodSignatures(bf->params, meth->params)) { // check for virtual functions. //* note: we don't need to care if 'bf' is the base method, because if we are 'isOverride', then we are also diff --git a/source/typecheck/dotop.cpp b/source/typecheck/dotop.cpp index df9944b7..1df3b6e7 100644 --- a/source/typecheck/dotop.cpp +++ b/source/typecheck/dotop.cpp @@ -462,8 +462,9 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d // ok. auto defn = fs->typeDefnMap[type]; - iceAssert(defn); + // note: if `defn` is null, then all the dcasts will fail and we'll + // fallthrough to the bottom. if(auto str = dcast(sst::StructDefn, defn)) { // right. From 6c241db477258cee34032973702c29892f75bc9d Mon Sep 17 00:00:00 2001 From: zhiayang Date: Fri, 11 Oct 2019 11:13:56 +0800 Subject: [PATCH 4/4] fix dumb optional arg codegen --- build/ultratiny.flx | 17 ++++++++++++----- source/codegen/call.cpp | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/build/ultratiny.flx b/build/ultratiny.flx index 138e51a0..67de758b 100644 --- a/build/ultratiny.flx +++ b/build/ultratiny.flx @@ -86,20 +86,25 @@ class B : A // issue #0: we basically don't really even check for overriding methods properly. // issue #1: co/contra-variance of return and parameter types for virtual methods -// issue #2: crashes when initialisers have default arguments?? +// issue #2: crashes when functions have default arguments?? // classes are a Bad Idea (tm) ): -struct Tmp +class Tmp { - k: int - m: int + var z: int - fn meth() -> int => k * m + init(x: int = 3, y: int = 7) + { + this.z = x * y + } } + @entry fn main() { + fn foo(x: int = 3, y: int = 7) -> int => x * y + // let a = B() // let q = a.foo(Y(c: 1)).data @@ -109,6 +114,8 @@ struct Tmp // let q = Tmp(k: 3, m: 7).meth() // let q = B().foo(Y(c: 1)).data + + let q = foo(x: 7) std::io::println("thing: %", q) } diff --git a/source/codegen/call.cpp b/source/codegen/call.cpp index 3fd41a28..b899f8fc 100644 --- a/source/codegen/call.cpp +++ b/source/codegen/call.cpp @@ -125,7 +125,7 @@ static std::vector _codegenAndArrangeFunctionCallArguments(cgn::Cod for(size_t i = 0; i < argExprs.size(); i++) { // this extra complexity is to ensure we codegen arguments from left-to-right! - auto arg = arguments[i].value; + auto arg = argExprs[i]; auto k = revArgExprs[arg]; auto infer = ft->getArgumentN(k);