nau/lasca-compiler
{ "createdAt": "2017-04-04T15:57:39Z", "defaultBranch": "master", "description": "Lasca is Scala shifted towards Haskell.", "fullName": "nau/lasca-compiler", "homepage": "", "language": "C", "name": "lasca-compiler", "pushedAt": "2018-10-27T13:57:35Z", "stargazersCount": 134, "topics": [ "haskell", "immutability", "scala", "simplicity" ], "updatedAt": "2025-11-18T15:36:03Z", "url": "https://github.com/nau/lasca-compiler"}Lasca Language
Section titled “Lasca Language”Lasca is Scala shifted towards Haskell.
Lasca is a LLVM-based statically or dynamically typed strict functional programming language. Simplified OCaml if you will.
It has a ‘dynamic’ compilation mode, meaning instant code generation without compile time type checking/inference, allowing instant compilation/execution cycle, and more freedom dynamic languages give.
It has a full type inference, parametric polymorphism, GC, algebraic data types, pattern matching, and type classes are coming soon.
Imagine
- Scala with fast compilation/start time, optional dynamic typing, and without null
- Go with ADTs, global type inference, and parametric polymorphism
- Haskell with decent records syntax, runtime polymorphism, and string interpolation
- OCaml with typeclasses, overloaded +-*/ for ints and floats, and do-notation
- Rust with garbage collector without <::>!?
- Erlang with types and fast execution
- Python with multithreading, pattern matching, and multiline lambdas
- TypeScript with indentation significant syntax, and LLVM
- Julia with static type checking, and zero-based indexing
Inspired by:
- Scala
- Haskell, Liquid Haskell, Linear Haskell, Idris
- OCaml/SML/F#/1ML
- Clojure (persisted data structures, HAMT/CHAMP)
- Go (CSP)
- Erlang (actors, immutability, minimalism)
- Python (docstrings, doctests, syntax)
- Julia
- Swift
- Nim
- Pony
- Koka (algebraic effects)
- light, non-symbol-polluted syntax (Python)
- indentation-based
- readability first
- fast development cycle
- presentation compiler for IDE integration
- IDE-friendly (intellisence ‘dot-autocomplete’, auto-formatting, compiler API)
- type-safe
- strict functional
- expression-based
- practical first, but as clean and concise as possible
- prefer things done one way
- LLVM backend
- JavaScript/WebAssembly backend (native or via LLVM/emscripten)
- GraalVM backend?
- no OOP and data subclassing/inheritance?
- syntactic sugar is ok
- no null
- annotations (Java/Python-style)
- annotation-based extensions
- macros based metaprogramming (like Scala Macros, Template Haskell)
- Concurrency Oriented Programming (Erlang). Objects are out. Concurrency is in.
- Gradual Typing
- Deferred Type Errors (runtime compilation mode, Haskell)
- Linear/affine types (Rust, Linear Haskell)?
- Liquid Type system (refinement types, Leon, Liquid Haskell) and Z3/CVC4 as proof assistant.
- Algebraic Subtyping for module system
- import features (Scala-like)
- compile-time and runtime reflection
- save/distribute AST (Scala TASTY). Full program optimization/reflection
- important things must be greppable and googlable, call it searchability :)
- compiler as a service: Language Server Protocol
- markdown/rst comments/docs, doctest (Julia, Python)
- CPS/Actors/π-calculus/STM?, non-blocking IO, reactive
Example
Section titled “Example”Current implementation uses braces and semicolons, but I consider adding indentation-based syntax, or semicolon inference.
-- Algebraic data type a la Haskelldata JValue = JNull | JNum(n: Float) | JString(s: String) | JBool(v: Bool) | JArray(v: [JValue]) | JObject(v: Map String JValue)
-- function argument type annotations are optional, compiler infers thosedef jsonToString(js: JValue) = match js { JObject(m) -> if Map.isEmpty(m) then "{}" else { println(toString(m)); res = Array.makeArray(m.size, ""); var idx = 0; Map.foreachWithKey(m, { k, v -> setIndex(res, idx.readVar, "\"${k}\": ${jsonToString(v)}"); idx := idx.readVar + 1; }); s = String.join(", ", res); "{ ${s} }" } JNull -> "null" JNum(n) -> toString(n) JBool(v) -> toString(v) JString(v) -> "\"${v}\"" JArray(v) -> { values = Array.map(v, jsonToString); toString(values); }}What Works Right Now
Section titled “What Works Right Now”- JIT and AOT compilation and execution (via LLVM OrcJIT)
- lasca -e hello.lasca to execute
- lasca hello.lasca to create a binary
- type inference
- dynamic typing mode (
lasca -e --mode dynamic hello.lasca) - ADTs, inner functions, out of order function definitions
- pattern matching
- calling external C functions
- string interpolation, UTF8 encoded immutable strings
- builtin types:
String,Bool,Int,Byte,Int16,Int32,Float,Array,ByteArray,Var,FileHandle - implemented
List,Option,Either,Map,ArrayBuffer - regular expressions with PCRE-2
- overloaded
+-*/operators
Package System
Section titled “Package System”Consider Nix as package manager
Compiler Modes
Section titled “Compiler Modes”- Dynamic Mode, aka Prototype Mode. Syntax is checked. All types are dynamically checked.
- Static Mode. Syntax is checked. Typechecking/inference, faster execution.
- Hardcore Liquid types enabled. (See Liquid Haskell) Proves checked. Array bounds checks eliminated.
Type System
Section titled “Type System”- Hindley-Milner by default, dependent types if needed
- traits, kind of type classes
- Liquid types as in Liquid Haskell
Memory Management
Section titled “Memory Management”GC, concurrent mark and sweep per actor/green thread GC Consider MultiCore Ocaml GC
for now, use Boehm conservative GC
- indentation significant (i.e. Python, Haskell)
- uppercase Typenames, lowercase idents and type arguments (Haskell/Scala style)
- pattern-matching
- ADT, traits, type classes
- easy C interoperability
- no exceptions (Go/Rust panic style errors)
- don’t overuse `’~!@#$%^&* symbols
- default immutability
- string interpolation: ”${ident} = ${expression}”
- multiline strings
- Uniform Function Call Syntax (Rust, D). For example, any function can be a method for its first argument:
def toString(s: String) = ... "Hello".toString def plus(l: Num, r: Num) 1.plus(2)- uniform select principle. Use (.) for record field selection, func calls, package name resolution etc
- UTF-8 strings
- Haskell-like application for type functions: Option Int, Either Int String, etc
Install on Mac OS using Homebrew
Section titled “Install on Mac OS using Homebrew”brew install boehmgc pcre2brew install nau/lasca/lasca-compilerSetup LASCAPATH environment variable. Add this to your .bash_profile
export LASCAPATH="$(brew --prefix lasca-compiler)/src"Try it!
echo 'def main() = println("Hello Lasca!")' > hello.lascalasca -e hello.lasca> Hello Lasca!Add bash completion config for lasca compiler options:
lasca --bash-completion-script lasca > $(brew --prefix)/etc/bash_completion.d/lascaBuild on Mac OS
Section titled “Build on Mac OS”You need LLVM 6.0 installed, and latest Haskell Stack.
brew install cmake boehmgc pcre2
brew install llvm-hs/llvm/llvm-6.0 # this compiles llvm from sources, make take some time
brew install haskell-stack
stack setupSetup LASCAPATH environment variable. Add this to your .bash_profile
export LASCAPATH="${lasca-compiler-src-dir}/libs/base"Add your ~/.local/bin directory to your PATH
export PATH=$PATH:~/.local/binBuild and install lasca compiler
make installAdd bash completion config for lasca compiler options:
lasca --bash-completion-script lasca > $(brew --prefix)/etc/bash_completion.d/lascaRun hello.lasca
lasca --exec examples/hello.lascaBuild on Ubuntu
Section titled “Build on Ubuntu”Requirements: Haskell Stack > 1.6, Cabal > 2.0, LLVM 6, CMake
Don’t install Haskell Stack from apt. It’s likely to be older than 1.6 and won’t be able to upgrade
Do this instead:
curl -sSL https://get.haskellstack.org/ | sh
sudo apt install llvm-6.0-dev libgc-dev zlib1g-dev cmakesudo add-apt-repository universesudo apt install libpcre2-devexport LASCAPATH="${lasca-compiler-src-dir}/libs/base"export PATH=$PATH:~/.local/binstack setupmake installlasca -e examples/hello.lascaCurrent n-body run
Section titled “Current n-body run”There are several implementation of [n-body problem]!( http://benchmarksgame.alioth.debian.org/u64q/nbody.html) Currently it’s quite slow due to boxing.
$ time lasca -e -O2 examples/nbody.lasca -- 50000000-0.169075164-0.169059907
real 7m13.261suser 7m39.476ssys 0m38.716s
find src -name "*.hs" | xargs cat | wc -l4738
cat rts/runtime.c rts/builtin.c rts/lasca.h | wc -l1324