Giter Site home page Giter Site logo

candy-lang / candy Goto Github PK

View Code? Open in Web Editor NEW
312.0 312.0 3.0 19.37 MB

๐Ÿญ A sweet, functional programming language that is robust, minimalistic, and expressive.

License: MIT License

Dart 0.28% TypeScript 1.71% Rust 96.90% Makefile 0.01% C 1.00% Nix 0.10%
compiler fuzzer hacktoberfest language language-server programming-language rust

candy's People

Contributors

ctiedt avatar dependabot[bot] avatar fpottbaecker avatar github-actions[bot] avatar jonaswanke avatar jwbot avatar marcelgarus avatar quag avatar skyz1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

candy's Issues

Package support breaks candy on Windows

Describe the bug
#390 introduced a bug where the module resolution inside packages fails to detect if a file is located in the package on Windows.

The underlying problem is the platform specific behavior of fs::canonicalize (see the documentation). This function returns a UNC-Path prefixed with \\?\ while package.to_path returns a DOS-Path without the prefix. strip_prefix then returns an error and the compiler thinks the file is not located in the package.

The dunce crate was created to combat this issue, but converting the UNC-path to a URL and back to a file path seems to be a quick workaround.

let canonicalized = Url::from_file_path(canonicalized)
    .expect("Invalid file path.")
    .to_file_path()
    .expect("File path conversion error.");

Expand IDE support

Lifecycle Messages

Document Synchronization

Language Features

Workspace Features

Remove `builtinPrint`

Builtin print should no longer be needed once we have robust stdio and can visualize traces.

Pattern Matching

Tasks

  1. P: Compiler: Frontend P: Compiler: VS Code Extension P: Core T: Feature
    JonasWanke
  2. P: Compiler: Frontend T: Feature
    JonasWanke
  3. P: Compiler P: Compiler: Frontend P: Compiler: Language Server T: Feature
    JonasWanke
  4. P: Compiler: Frontend T: Fix
  5. P: Compiler: Frontend T: Feature
    JonasWanke

Create packages

Create packages:

Packages

  1. 2 of 5
    Epic P: FileSystem T: Feature
  2. 1 of 3
    Epic P: Http T: Feature
  3. T: Feature
    skyz1
  4. 2 of 4
    Epic P: Csv T: Feature
  5. T: Feature
    skyz1
  6. P: ComplexNumber T: Feature
    JonasWanke
  7. P: AnsiEscapeSequences T: Feature
    JonasWanke
  8. P: Ascii T: Feature
    JonasWanke

Optimize VM Byte Code

Ideas:

Tasks

Fuzz formatter

  • check idempotence: running the formatter on formatted code shouldn't change anything
  • check AST equality: the AST of formatted code should be the same as the AST of unformatted code

Tags

Instead of symbols, we want to have tags that can also have an optional associated value. Our current symbols will just be named tags. Tags without an associated value can be called just like functions to associate a value with them.

tagWithoutValue = Foo
tagWithValue = Foo 3
newResult = Ok 4
error = Error "That didn't work."
dynamicallyCreatedTag = tagWithoutValue 5
nestedTag = Foo (Bar 3)

Formatter makes pattern match invalid

Currently, the formatter takes this code:

is value := value %
  Ok _ | Error _ -> True
  _ -> False

and turns it into this:

is value := value %
    Ok _ | Error _ -> True
    _ -> False

This code is invalid though.

Introduce packages and restructure the CLI

Our current CLI is kind of weird โ€“ you have to specify a .candy file including the extension and we just assume that the current working directory is the project. I want to look into optimizations (and in particular specifying custom optimization guidance using a scoring function) next.

Just to recap the distinction of packages vs. modules, I believe this is our current definition:

  • Modules evaluate to a Candy value. For example, code modules evaluate to a struct containing the exported definitions, asset modules evaluate to a list containing the bytes. Modules are not necessarily self-contained because they can import other modules with use.
  • Packages are a subset of modules. They are self-contained, so while modules inside of them can import each other, no relative import can cross the package boundary in either direction. Packages can also contain functionality for publishing them or building a binary.

I thought a bit about how Candy packages could work and how they could interact with our CLI.

What Makes a Package a Package

My proposal on how to distinguishing packages from modules: Packages can only be folders and next to the top-level _.candy file, they must also contain a package.candy file containing information on the package itself. Here's what a minimal package might look like:

foo/
  _.candy
  package.candy

When invoking the CLI, it will look if the current working directory is a package. If it isn't it will walk up the hierarchy and stop either if it finds a package.candy file or it doesn't find a _.candy file indicating a folder is a Candy module.

We probably also want to allow specifying packages that are not the current working directory, e.g. like this: candy --package path/to/package/folder build.

The Package Configuration File

The big remaining question is what the package.candy file contains. This depends on what you can do with the package. Later on, packages can be built into binaries or published for others. For now, the package.candy could contain information on how to optimize the module using a custom scoring function. For example, if we want to tell the MIR optimizer to optimize the Fibonacci program so that the binary executes fibonacci 610 as fast as possible, we might have the following files:

# _.candy

[int, list] = use "Core"

fibonacci n =
  ...

main environment :=
  n = environment.args | list.get 0 | int.parse
  fibonacci n | print
# package.candy (for me, GitHub hides it but you may have to scroll in this code section)

[int] = use "Core"

# Executed when running `candy publish`. The `environment` contains information about the
# dev environment such as the arguments given to the command, environment variables, etc.
publish environment :=
  # Assuming tags are supported, this only publishes the `Fibonacci` export from the
  # `_.candy` file. Alternatively, you can also use `Everything` to publish the entire
  # module. We may want to think about restricting this to export that statically resolve
  # to a struct (so that `use SomePublicPackage` is always a struct), but we could also
  # think about allowing exporting single values.
  [
    Value: Only Fibonacci,
    Name: "MyPackage",
    Description: (use "README.md") | string.parse,
    Version: 3,
    ...
  ]

# Executed when running `candy build`.
build environment :=
  [
    EntryPoint: Main,
    # A custom scoring function where lower scores are better.
    OptimizationScoring: { artifact ->
      int.add
        artifact.numInstructions
        artifact.run Main 610
    },
    Plugins: [
      Stdin,
      Stdout,
      Variables,
      Random,
      HttpsServer,
    ],
    Target: Wasm,
  ]

This way, we can completely customize the build using arguments (thereby replacing things such as Flutter flavors).

Commands

I think we should support these commands:

  • candy analyze: Builds the project (maybe up until the HIR?) and reports all errors.
  • candy build: Builds the project according to the build function in the package.candy.
  • candy run: Builds the project and runs it with the given arguments.

For simple scripts, we may want to allow standalone modules that can be run independently. I'd suggest these are treated similarly to being the sole content of a package with a default build configuration.

candy --file my/Downloads/something.candy run

Because these are self-contained, they can't import any other files โ€“ to do that, you have to first create a package.

Running individual functions

Perhaps a bit unrelated, I think it would also be useful to have the ability to run arbitrary functions from the command line.

candy --function examples/fibonacci.candy:fibonacci run 610

Does a grammar file 'candy.g' exist???

Hey guys,

I am looking quite excited at your 'new' programming language!

I just wanted to know if you use or have a grammar file for these Candy language? That grammar file could (!) be used to make Candy as an interpreted language as well.

Add tests

While we do have fuzzing for the Core library, a few simple unit tests would also go a long way for catching obvious bugs.

FEATURE: provide candy compiler/lsp server for linux/macosx

Hey guys,

I am quite more excited since the last issue! It`s fantastic that candy got it first release!!!! ๐Ÿ‘ YEHA! ๐Ÿ‘ฏ

I looked into the tools you provided with the first release and noticed that these tools are just for windows. Is it possible to provide these tools for linux and/or macosx in the next releases?

Btw your extension for visual studio code works just as expected, excellent!

Again, thank you very much for you work!

Fix the evaluation order of pipe expression by keeping it in the AST

Currently, foo 0 | (bar 1) first evaluates bar 1, then foo 0, and then calls the result of bar 1 with the result of foo 0. This is because pipes are not preserved in the AST, instead the expression gets lowered to the equivalent of (bar 1) (foo 0).

We should keep pipe expressions in the AST and then fix the AST to HIR lowering so that the above code evaluates foo 0, then bar 1, and then calls the result of bar 1 with the result of foo 0.

Fix renaming in lambda

Describe the bug

main := { _ ->
  foo = 123 # Rename doesn't work
  โœจ.print foo # Rename works
}

Potential optimizations

Some ideas about optimizations we could implement:

Tasks

  1. P: Compiler: Frontend T: Performance
    JonasWanke
  2. 0 of 2
    Epic P: Compiler: VM T: Feature
  3. P: Compiler: Frontend T: Performance
    JonasWanke
  4. P: Compiler: CLI P: Compiler: Fuzzer P: Compiler: Language Server P: Compiler: VM T: Feature T: Performance
    JonasWanke
  5. P: Compiler: CLI P: Compiler: Formatter P: Compiler: Fuzzer P: Compiler: Language Server P: Compiler: VM T: Feature T: Performance
    JonasWanke

Visualize traces

Think about and implement visualizing Candy function executions.

Code Action ideas

Tasks

Disallow passing named closures as parameters? Or auto-propagate the fault to the caller?

If functions were responsible for fulfilling the needs of functions given to them as arguments, every higher-order function would have to include a try block or something similar and then re-propagate that responsibility to the caller.

That's why we should establish the rule that inside higher-order functions, you shouldn't have to care about the needs of functions given as parameters. Instead, the caller is responsible for giving you only functions that accept the values that you call them with.

Semantically, this would equate to wrapping functions in closures.

bar a = ...

# A call to higher-order function foo:
foo bar

# Would really be equivalent to this:
foo { a -> bar a }

Parser doesn't parse function with comment on same line

Currently, the parser doesn't parse this code:

is value := # โœจ.print "is result?"
  value %
    Ok _ | Error _ -> True
    _ -> False

It complains that value is not defined, so it seems like it stops parsing the function after the first line.

Improve pattern match panic messages

[Foo, 1, {a}] = [Foo, 2, {A: B]] could generate a message like Expected `[_, 1, _]`, got `[_, 2, _]`.

When checking individual cases of a match, we don't want to construct the error messages eagerly. For the vast majority of cases, at least one case will match, so concatenating (and thereby allocating) lots of strings slows down the code by a lot.
Instead, when no case matches, we should revisit all the cases and build a nice error message, detailing why each case doesn't match.

Hi, future me! Past me here :)
For performance, we take out building the error messages when cases don't match. We should revisit this in the future. Our current state where we build error messages for non-matching cases: a68dbb9

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.