All Projects → KCreate → Charly Vm

KCreate / Charly Vm

Fibers, Closures, C-Module System | NaN-boxing, bytecode-VM written in C++

Programming Languages

bytecode
52 projects

Projects that are alternatives of or similar to Charly Vm

Lioness
The Lioness Programming Language
Stars: ✭ 155 (+134.85%)
Mutual labels:  compiler, ast, lexer, parser
Snapdragon
snapdragon is an extremely pluggable, powerful and easy-to-use parser-renderer factory.
Stars: ✭ 180 (+172.73%)
Mutual labels:  compiler, ast, lexer, parser
Cub
The Cub Programming Language
Stars: ✭ 198 (+200%)
Mutual labels:  compiler, ast, lexer, parser
Exprtk
C++ Mathematical Expression Parsing And Evaluation Library
Stars: ✭ 301 (+356.06%)
Mutual labels:  compiler, ast, lexer, parser
Tiny Compiler
A tiny compiler for a language featuring LL(2) with Lexer, Parser, ASM-like codegen and VM. Complex enough to give you a flavour of how the "real" thing works whilst not being a mere toy example
Stars: ✭ 425 (+543.94%)
Mutual labels:  compiler, ast, lexer, parser
Csstree
A tool set for CSS including fast detailed parser, walker, generator and lexer based on W3C specs and browser implementations
Stars: ✭ 1,121 (+1598.48%)
Mutual labels:  ast, lexer, parser
Webassemblyjs
Toolchain for WebAssembly
Stars: ✭ 566 (+757.58%)
Mutual labels:  compiler, ast, parser
Graphql Go Tools
Tools to write high performance GraphQL applications using Go/Golang.
Stars: ✭ 96 (+45.45%)
Mutual labels:  ast, lexer, parser
Participle
A parser library for Go
Stars: ✭ 2,302 (+3387.88%)
Mutual labels:  ast, lexer, parser
Phplrt
PHP Language Recognition Tool
Stars: ✭ 127 (+92.42%)
Mutual labels:  compiler, ast, parser
Ratel Core
High performance JavaScript to JavaScript compiler with a Rust core
Stars: ✭ 367 (+456.06%)
Mutual labels:  compiler, ast, parser
Php Parser
🌿 NodeJS PHP Parser - extract AST or tokens (PHP5 and PHP7)
Stars: ✭ 400 (+506.06%)
Mutual labels:  ast, lexer, parser
Minigo
minigo🐥is a small Go compiler made from scratch. It can compile itself.
Stars: ✭ 456 (+590.91%)
Mutual labels:  compiler, lexer, parser
Felix
The Felix Programming Language
Stars: ✭ 609 (+822.73%)
Mutual labels:  compiler, coroutines
Tiny Compiler
A tiny evaluator and compiler of arithmetic expressions.
Stars: ✭ 680 (+930.3%)
Mutual labels:  compiler, ast
Postcss
Transforming styles with JS plugins
Stars: ✭ 25,612 (+38706.06%)
Mutual labels:  ast, parser
Meriyah
A 100% compliant, self-hosted javascript parser - https://meriyah.github.io/meriyah
Stars: ✭ 690 (+945.45%)
Mutual labels:  ast, parser
Marked
A markdown parser and compiler. Built for speed.
Stars: ✭ 26,556 (+40136.36%)
Mutual labels:  compiler, parser
Esprima
ECMAScript parsing infrastructure for multipurpose analysis
Stars: ✭ 6,391 (+9583.33%)
Mutual labels:  ast, parser
Php Parser
PHP parser written in Go
Stars: ✭ 787 (+1092.42%)
Mutual labels:  ast, parser

Charly Programming Language

What is Charly?

Charly is a programming language with the following goals:

  • Syntax similar to JavaScript (Compatibility is not a goal)
  • Easy way to write C extensions
  • Single-threaded work-queue for charly code
  • Async IO, multithreadable C code
  • Small and simple standard library

Charly was not created with the intention of it being used as a production level language for anything important. It's main purpose is to teach other programmers how to write the basic components of a programming language. This includes the various stages of producing an Abstract Syntax Tree, how to perform manipulations on that tree and finally how to generate bytecodes that can then be executed in a custom virtual machine.

Charly's implementation contains many interesting things, such as NAN-Boxing, a C-Module system using dlopen, a computed-goto main-switch, a mark-and-sweep garbage collector and a single-threaded task-queue backed by an asynchronous, multithreaded worker-queue.

Example code

Channels

// Create a new channel
const c = new Channel()

// Writer loop
spawn(->{
  let i = 0
  loop {
    c.write(i)
    i += 1
  }
})

// Reader loop
spawn(->{
  loop {
    const msg = c.read()
    print("Message: " + msg)
  }
})

// Output:
// Message: 0
// Message: 1
// Message: 2
// Message: 3
// Message: 4
// ...

Promises

The spawn.promise method is a shorthand for the regular new Promise(->(resolve, reject) {...}) kind of way to creating a promise. The created promise resolves once the callback returns or rejects if the callback throws an exception.

const p = spawn.promise(->"Hello world!", 1.second())

p.then(->(result) {
  print("Got result: " + result) // Got result: Hello world!
})

You can also synchronously wait for a promise to finish. This currently active thread pauses and will resume once the promise resolves or throw an exception if it gets rejected.

const p = spawn.promise(->"Hello world", 1.second())

// The wait method returns the value the promise resolved with.
// If the promise got rejected, it will throw
const result = p.wait()

print(result) // "Hello world!"

Turning asynchronous into synchronous flow

// Implementation of the sleep method using standard library constructs
func sleep(duration) {

  // The Notifier allows the user to pause and
  // resume different threads of execution
  const n = new Sync.Notifier()

  // notify_one will resume one waiting thread
  spawn.timer(->n.notify_one(), duration)

  // Wait until we are notified to resume
  n.wait()
}

print("Hello")
sleep(1.second())
print("World")

Closures

// This function returns another function which, when invoked,
// will return the current value of the counter and add 1 to it
func create_counter {
  let i = 0

  return ->{
    const v = i
    i += 1
    return v
  }
}

const counter = create_counter()
counter() // => 0
counter() // => 1
counter() // => 2

Exceptions

try {
  throw "Hello World"
} catch(e) {
  e // => "Hello World"
}

try {
  // do some things here
} finally {
  // The `finally` handler gets invoked no matter if an exception has been caught or not

  print("Hello World")
}

Classes

class Greeter {
  property name

  greet {
    print("Good morning " + @name)
  }
}

class RudeGreeter extends Greeter {
  constructor(name) {
    super("stupid " + name)
  }

  greet {
    print("...oh no, not him again...")
    super()
    print("...now go away...")
  }
}

const greeter      = new Greeter("Leonard")
const rude_greeter = new RudeGreeter("Leonard")

greeter.greet()
// Good morning Leonard

rude_greeter.greet()
// ...oh no, not him again...
// Good morning stupid Leonard
// ...now go away...

Tickers

const t = spawn.ticker(->(i) {
  print("Iteration: " + i)
}, 250.ms())

t.then(->{
  print("Ticker iterations: " + t.iterations)
})

spawn.timer(->t.stop(), 2.seconds())

Extending primitive classes

Mocking Spongebob Meme

String.prototype.mockify = func {
  const sentence = self.lowercase()

  // Split the sentence into words
  const words = sentence.split(" ")

  // Change the case of each character
  let uppercase = false
  const mocked_words = words.map(->(word) {
    word.map(->(character) {
      if !uppercase { uppercase = true;  return character }
      if uppercase  { uppercase = false; return character.uppercase() }
    })
  })

  mocked_words.join(" ")
}

print("You should not use memes in example code".mockify())
// => yOu ShOuLd NoT uSe MeMeS iN eXaMpLe CoDe

Teaching Features

Via the executable arguments, you can make the charly compiler print out various data structures that are being produced during the compilation phase.

func greet(n) {
  print("Hello " + n)
}

greet("leonard")

Tokens

Token dumping

Abstract Syntax Tree

AST dumping

Bytecode

ASM dumping

Contributing

All contributions are welcome, no matter how small or big.

  1. Fork it (https://github.com/KCreate/charly-vm/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am "Add some feature")
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Installation

You're going to need a Compiler supporting C++17. I am currently using the clang 10 compiler, I don't know if it works on other compilers.

  1. git clone http://github.com/KCreate/charly-vm
  2. Build
    • Development: make or make rebuild
    • Production: make production
    • Profiled-Production: make profiledproduction
      • The profiledproduction method will first build a production binary. Using the optimized binary, it will execute the file examples/runtime-profiler.ch, which tries to touch every part of the language at least once. It then uses this profile to generate an even more optimized version. I currently don't have any benchmarks to prove this claim, so don't quote me on this.
  3. Set the CHARLYVMDIR environment variable to the project's root folder CHARLYVMDIR=/home/user/github/KCreate/charly-vm
  4. (Optional) Execute the unit-test suite to make sure everything works correctly bin/charly test/main.ch
  5. Done!

Executing unit tests

Execute the unit-test suite via bin/charly test/main.ch. To disable stack traces in error messages add the --hide-stacktraces flag.

$ bin/charly test/main.ch
Charly Unit Testing Framework
........................................................................................................................................................................................................................................................................................................

All tests have passed

Command-line options

$ bin/charly -h
Usage: charly [filename] [flags] [--] [arguments]

Default
  -h, --help
      Prints the help page

  -v, --version
      Prints the version

  -l, --license
      Prints the license

  --vmdir
      Prints the CHARLYVMDIR environment variable

Dump
  --skipexec
      Don't execute the code

  --dump <filename>
      Add file to list of files to be dumped

  --dump_ast
      Dump the AST of the input file

  --dump_tokens
      Dump the tokens of the input file

  --dump_asm
      Dump the compiled bytecode of the input file

  --asm_no_offsets
      Do not print offsets in dumped bytecode

  --asm_no_branches
      Do not print branches in dumped bytecode

  --asm_no_func_branches
      Do not print function branches in dumped bytecode

Debugging
  --instruction_profile
      Profile the execution time of individual bytecodes

  --trace_opcodes
      Display opcodes as they are executed

  --trace_catchtables
      Trace catchtable enter / leave

  --trace_frames
      Trace frame enter / leave

  --trace_gc
      Display GC debug output

Examples:

    Executing a file:
    $ charly file.ch

    Dumping generated bytecodes for a file:
    $ charly file.ch -fskipexec -fdump_asm

    Dumping generated AST for a file:
    $ charly file.ch -fskipexec -fdump_ast

    Disabling the cli-parser using '--'
    $ charly dump-argv.ch -- -fdump_asm -fskipexec

Vim syntax highlighting & indent support

In the folder vim_syntax_files there are three files you can install into your local .vim folder to gain some syntax highlighting and indentation support for vim. They are originally for the JavaScript language but I modified them to suit my own needs. The original sources are linked at the top of the respective files.

Credits

Mentions

I would like to mention the following projects and people:

  • Crystal Programming Language This project got me into language development in the first place. By studying its source code, I taught myself how to write a parser for complex languages and how to model an AST. The first version of the Charly language was also written in Crystal, before I moved on to C++.

  • The Wren Programming Language I learned a lot from this project, most notably how to implement NaN-Boxing.

  • Eli Bendersky's Website Eli's articles on language-dev related topics were of great use to me and I learned a lot from them. Most articles in the #compilation section of his website contain very useful and interesting information.

  • Kartik Agaram and Max Bernstein They both helped me a lot during the learning process and I have always been able to bounce my ideas off of them, getting valuable feedback.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].