Code Monkey home page Code Monkey logo

cobalt-lang's People

Contributors

dependabot[bot] avatar fluxflu avatar matt-cornell avatar treemcgee42 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

cobalt-lang's Issues

Handle incorrect annotations better

As of right now, there are separate TokenKinds for intrinsics and annotations, despite being difficult to tell apart at the lexing phase. As a workaround, the intrinsics registry is checked, but this has a problem: it assumes that anything not recognized is an annotation.

While this could be manageable on its own, the error doesn't print correctly for some reason. This makes it difficult to tell what went wrong or where the error is, which could easily detract from Cobalt's usability.

To fix this, I propose merging the Intrinsic and Annotation variants into IntrinOrAnn(&'src str, &'src str, usize). When lexing, the tokenizer will lex the annotation arguments, roll back to the start, lex it as tokens, then store the token count. In the case of an annotation, the following tokens can be skipped, and for an intrinsic, the extra fields can be ignored.

Hang on unmatched delimiter in function declaration

Example

Consider this test file, test.co:

fn add(x: i32 = 1i32: i32 = x;

Try compiling like this:

> co aot test.co -e obj

For me, the compiler hangs with no output.

Ideas

The hanging happens here:

https://github.com/matt-cornell/cobalt-lang/blob/9442a2444d8018c8188280ee66938c52cc8d7827/cobalt-parser/src/lib.rs#L466

The issue is that process() never returns None. This, in turn, is because param() never returns an error. The relevant line seems to be

https://github.com/matt-cornell/cobalt-lang/blob/9442a2444d8018c8188280ee66938c52cc8d7827/cobalt-parser/src/lib.rs#L398

According to LLDB, str eventually becomes ;\n and param() keeps getting called with the same str. We can add a check for ; as well, which does solve the hanging, but doesn't properly update pointer (I think) for the parsing string. This results in an ugly error message:

> co aot test.co -e obj
(cobalt errors)

thread 'main' panicked at 'misaligned pointer dereference: address must be a multiple of 0x8 but is 0x1', cobalt-ast/src/varmap.rs:117:66

(stack backtrace)

thread caused non-unwinding panic. aborting.
Abort trap: 6

Better error message for constant variable reassignment

Consider the following code:

fn add_one(num: &i32) = {
    num += 1;
};

The compiler will correctly throw an error, because num is not mutable, but the error isn't the best:

binary operator "+=" is not defined for types `i32` and `i32`

The error message should ideally communicate that num is constant.

The situation is similar for variable definitions:

let x = 3i32;
x = 0i32;

will throw the same binary operator not defined error.

Improve type inference

Decaying types should be used less, in favor of bidirectional typing. Basically, code like this should work:

# local scope
let x = 10;
let y: i32 = x + 1;

Currently, this fails because 10 decays to i64 when stored in x, which then can't be narrowed to an i32, but there's nothing in the code forcing this to be the case. With some lookaheads, this could allow for more type hints to be omitted.

Additionally, a "hole" type should be added for cases in which only a partial type hint is necessary. Tentatively using ? as a placeholder, we could get something like this:

# global scope
fn returns_a_reference(): &mut i32;
# local scope
let x: &mut ? = returns_a_reference();
++x;

Alternate bases for numeric literals

How do we manage to forget this every parser rewrite? Anyways, binary, octal, and hex literals need to be re-implemented (0b, 0o, and 0x prefixes respectively).

Add traits

Marker traits

A trait with no functions can be used as a marker, and is auto-implemented in the following way:

trait trait_1;

type Type1 = i32;
impl Type1: trait_1;

Trait arithmetic

A few operations can be performed on traits to compare them and create new ones.

Addition

The result of adding two traits is a trait which requires its summand traits to be implemented for a type before it itself can be implemented.

trait trait_a;
trait trait_b;

trait compound_trait = trait_a + trait_b;

Less than

We say that trait_a < trait_b if implementing trait_b would be sufficient but not necessary to implement trait_a.

Note that simply implementing trait_b on a type does not automatically implement trait_a on that type. However, after implementing trait_b, one can automatically implement trait_a:

trait trait_a :: {
  fn foo();
};
trait trait_b :: {
  fn foo();
  fn bar();
};

type Type1 = i32;
impl Type1: trait_b :: {
  fn foo() = {
    # ...
  };

  fn bar() = {
    # ...
  };
};

# automatic implementation
impl Type1: trait_a;

Equality

trait_c is considered equal to trait_d if and only if implementing trait_c is necessary and sufficient to implement trait_d. For example, taking the traits as defined above,

trait trait_c = trait_b;
trait trait_d = trait_a + trait_b;

The reason trait_c == trait_d is because trait_a < trait_b, so trait_a + trait_b <= trait_b + trait_b == trait_b. But also trait_b <= trait_a + trait_b (trait addition has the same semantics as adding positive integers).
ย 

Automatic implementation

Scoping

Dynamic dispatch

There are situations where calling trait functions will result in dynamic dispatch, but this is not always the case. If the only thing known about an object is that it implements a trait, then calling a trait function on that object will result in dynamic dispatch. However, if the type of the object is known at compile time when calling a trait function, the compiler can directly include a call to the specific implementation of the trait function.

In the following few examples, we will use the following trait, and type which implements that trait:

trait trait_1 :: {
  fn trait_fn();
};

type Type1 = i32;
impl Type1: trait_1 :: {
  fn trait_fn() = {
    3i32
  };
};

This is an example of where dynamic dispatch occurs.

# Box syntax tbd
fn foo(): Box<trait_1> = {
  # ...
};

fn main(): i32 = {
  let my_obj = foo();
  my_obj.trait_fn()
}

This is an example of where dynamic dispatch does not occur.

fn bar(x: impl trait_1): i32 = {
  x.trait_fn()
};

fn main(): i32 = {
  let my_obj = 3i32 :? Type1;
  bar(my_obj)
};

Compile-time enforcement

It's useful to ensure at compile-time that dynamic dispatch does not occur. For instance, dynamic dispatch on hot paths can have a significant impact on performance.

To that end, we propose the following syntax:

fn bar(x: @kact impl trait_1): i32 = {
  # ...
};
(`@kact` stands for "known at compile time").

Take error list by reference

All Cobalt APIs return a Vec<CobaltError>, which leads to a lot of unnecessary allocations. Replace this by taking a &mut Vec<CobaltError> as a parameter instead, which allows for allocation reuse and such.

Improve import method

Right now, imports are resolved lazily. They're simply stored in a Vec, and checked for every variable. This leads to issues with both performance, since the compiler traverses all of the possibilities, and error specificity, since little is known about the variables at the time. The only benefit that they had was that they could be declared out of order, which is already allowed now.

To fix this, they should be changed to be eager. Symbols should be able to have a path to another import, and any invalid path components or empty globs should be made errors at the declaration site.

Pointers to mutable data: parsing and functionality

Currently there is no way to pass a pointer to mutable data to a function:

fn changer(x: *mut i32) = {
  *x = 4;
};

fn main() = {
  let mut x = 0i32;
	
  # compilation error
  changer(&mut x);

  0
};

I was able to get rid of the parsing errors in b10823b but the above code now results in a seg fault. Right now that change is only for ints-- I wanted to make get this example working before extending that solution to other types.

Function parameter parsing function

  • The parser is hanging on invalid function parameters, because the function which parses parameters is not advancing the input string when it encounters an error (resulting in a constant stream of errors).
  • Not parsing "mut" keyword.
  • Doesn't support unnamed parameters (is this intentional?)

Fix the package manager

It's been tried twice. It's failed twice. Make it work.

Goals:

  • Respect that some packages have multiple targets, only compile necessary targets.
  • If no targets are listed, look for a target with a default-ish name, something like default or lib (TODO: figure out what it should be?).
  • Targets of the same package should have the same version, except for cases in which multiple versions of a package are necessary.
  • Both source code and compiled outputs should be stored in a global location, such as in $COBALT_DIR.
  • Source code and compiled outputs need to be usable with the commands for compiling individual files, perhaps with a full package dependency spec parsing.
  • Support downloading prebuilt binaries.
  • Do all of this with readable code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.