Petal compiler, specification, and tools

petal.md 4.5KB

Petal

Problem domains

I want a language that’s good for application development. GUI and webserver style. I want it to be good for writing efficient code easily. I want it to have a garbage collector, and I have absolutely no interest in disabling the garbage collector.

On the other hand, we do have to interface with native code, and part of that is making manual allocations work.

Principles and theoretical backing

I don’t think Petal will be a particularly theoretically bound language. It’s not an ideas language.

Programming paradigms

Procedural, structured, OOP, DbI, moderate functional, contracts. More functional than D, far less than a typical ML.

Inspiration languages

Obviously using D as an inspiration for DbI. C# is one of the main inspirations for OOP / structured / procedural code. I want to use Smalltalk-style message-passing, kind of, but it’s probably more natural to use more traditional function calls.

I want to see how far I can push purity without sacrificing performance.

Look and feel

For development

I’m going to start out with D-style syntax. It’s worked out a number of kinks. Later I’ll look at syntax again and see if I can make something I like more. Mainly I want syntax that I know basically works.

I’m going closer to C# here, actually.

  • Importing stuff: using feels best
  • namespace instead of modules
  • Imports anywhere
  • D template syntax (for now)
  • Pointer!T instead of T*, at least at first; has deref builtin function. (This makes it ugly to use pointers. We’ll also have rawptr.)

Ideal

I want something like:

# comment
let int a!           # auto-initializes a
writeln a.
let b = a:to float.  # cast
let Object c!        # calls default ctor

class MyClass
{
    # Not sure how this works with function call interface
    @Annotation
    unit foo
    {
        writeln "this is the foo method".
    }

    int sum(int a, int b)
    {
        return a + b.
    }
}

Personal value features

  • Local variables mutable by default
  • Function params const by default
  • Modulus should obey: (a % b) == ((a % b) + b) % b
    • The sign of the result matches the sign of the divisor
    • Like in Python
  • Attributes
    • All attributes are values.
  • Visibility and virtual dispatch are mostly orthogonal.
    • A file-private function can be overridden by other things in the same file, so it’s virtual.
    • A public final function can’t be overridden, and if it doesn’t override anything, it’s not virtual.
    • A type-private, disallow-children function can’t be overridden, so the compiler makes it virtual as an optimization.
  • Default function arguments are arbitrary expressions evaluated at the call site if the thing isn’t provided. Python allows this but makes an implicit static variable, while D says it has to be a compile-time constant. If we said compile-time constant, that would mean bringing in null everywhere, and I don’t want null.
  • Override functions don’t need to mention their return types maybe?

Metaprogramming

I want easy metaprogramming. This means:

  • Analyzing types with code should be straightforward
    • Like: typeof(foo).meta.methods[0].name -- object model, not weird pseudofunctions
    • Should be able to use normal code to look at it
    • Some convenience method for checking for a function with a given signature: type.hasFunction(int foo(string, string))
  • Defining types with code should be straightforward
    • String mixins are the most flexible way…
    • This seems to be crying out for a template engine, but let’s watch for patterns.
  • Inserting code should be straightforward
  • Most everything you do at runtime should be available at compiletime

Foreign function interface

How easily do I want to be able to interface with C and C++? Are there other languages I want to interface with?

Well, I’m just one person. So I want the interface to be pretty simple, at least for C. I think there’s a lot less C++ code I want to interact with. I do want GObject to be straightforward to work with, but probably no special support for it.

Compiler

Parser options:

  • pegged
  • antlr
  • flex / bison

Pegged is slow and memory-hungry. Antlr has a terrible API for adding fields to your AST nodes, so I’d need to create a semantic tree from the parse tree.

Backend options:

  • llvm
  • c
  • some pre-existing virtual machine / bytecode

We’ll probably need to use a bytecode thingy for running code at compile-time, sandboxed.

Testing:

  • use fuzzer
  • hand-rolled test cases

Code organization

The unit of encapsulation is the library.