An Elm-inspired language that transpiles to TypeScript
Homepage: https://derw-lang.github.io/
Follow Derw on Twitter: https://twitter.com/derwlang
npm install --save-dev derw
or
npm install -g derw
npx derw
To get started:
Start a package via `derw init`
Compile via `derw compile`
Or compile and test via `derw test`
Or find out info via `derw info`
You can run the derw compiler via npx. You must provide files via --files
or be in a package directory.
npx derw
Let\'s write some Derw code
To get started:
Provide entry files via --files
Or run me without args inside a package directory
--files [string...]: Filenames to be given
--test : Test the project
--target ts | js | derw | elm | english : Target TS, JS, Derw, or Elm output
--output string: Output directory name
--verify : Run typescript compiler on generated files to ensure valid output
--debug : Show a parsed object tree
--only string: Only show a particular object
--run : Should be run via ts-node/node
--names : Check for missing names out of scope
--quiet : Keep it short and sweet
-h, --help : This help text
You can find a bunch of examples in examples, along with the Typescript they generate. But the general gist is: Elm-compatible syntax where possible.
type Result a b
= Err { error: a }
| Ok { value: b }
asIs : Result a b -> Result a b
asIs result =
case result of
Err { error } -> Err { error }
Ok { value } -> Ok { value }
-
Arrays
[ ]
,[ 1, 2, 3 ]
,[ [ 1, 2, 3 ], [ 3, 2, 1 ] ]
-
Booleans
true
,false
-
Boolean equality
1 < 2
,1 <= 2
,1 == 2
,1 != 2
,1 > 2
,1 >= 2
-
Boolean operations
true && false
,not true
,true || false
-
Strings
""
,"hello world"
-
Format strings
``
,`Hello ${name}`
-
Numbers
-1
,0
,1
,-1.1
,1.1
-
Addition
1 + 2
,"Hello" + name
-
Subtraction
2 - 1
-
Multiplication
2 * 1
-
Division
2 / 1
-
Pipe
[1, 2, 3] |> List.fold add
,List.fold add <| [1, 2, 3]
-
Compose
>>
,<<
-
Constants
hello = "hello world"
-
Function definitions
-
Lists
[ 1, 2, 3 ]
,[ "hello", "world" ]
-
List ranges
[ 1..5 ]
,[ start..end ]
add : number -> number -> number add x y = x + y
-
Function calls
three = add 1 2
-
Module references
three = List.map identity [ 1, 2, 3 ]
-
Union types
type Result a b = Err { error: a } | Ok { value: b }
-
Type variables
type Thing a = Thing a
-
Type aliases
type User = { name: string }
-
Object literals
user: User user = { name: "Noah" }
-
Object literals updates
user: User user = { ...noah, name: "Noah" }
-
Imports
import List import Result exposing ( map ) import something as banana
-
Exports
exposing ( map )
-
Let statements
sayHiTo : User -> string sayHiTo user = let name = user.name in "Hello " + name sayHelloTo : User -> string sayHelloTo user = let getName: User -> string getName user = user.name in "Hello" + getName user
-
If statements
type Animal = Animal { age: number } sayHiTo : Animal -> string sayHiTo animal = if animal.age == 1 of "Hello little one!" else "You're old"
-
Case..of
type Animal = Dog | Cat sayHiTo : Animal -> string sayHiTo animal = case animal of Dog -> "Hi dog!" Cat -> "Hi cat!"
-
Destructing in case..of
type User = User { name: string } sayHiTo : User -> string sayHiTo user = case user of User { name } -> "Hi " + name + !"
-
strings in case..of
-
defaults in case..of
sayHiTo : string -> string sayHiTo name = case name of "Noah" -> "Hi " + name + !" default: "I don't know you"
-
List destructing
sum: List number -> number sum xs = case xs of [] -> 0 y :: ys :: [] -> y + ys z :: zs -> z + sum zs default -> 0
-
List destructing with string values
sum: List string -> number sum xs = case xs of [] -> 0 "1" :: ys :: [] -> 1 + 2 "2" :: zs -> 2 + sum zs default -> 0
-
List destructing with union types values
sum: List (Maybe number) -> number sum xs = case xs of [] -> 0 Just { value } :: rest -> value + sum rest Nothing :: rest -> sum rest default -> 0
-
Constructing union types
type User = User { name: string } noah = User { name: "Noah" }
-
Accessors
type alias User = { name: string } names = List.map .name [ { name: "Noah" }, { name: "Dave" } ]
-
Nested accessors
type alias Group = { person: { name: string } } names = List.map .person.name [ { person: { name: "Noah" } }, { person: { name: "Dave" } } ]
-
Errors on type name collison
The name `Person` has been used for different things. 8 - 10: ``` type Person = Person { name: string } ``` 11 - 14: ``` type alias Person = { name: string } ```
-
Errors on function name collison
The name `isTrue` has been used for different things. 0 - 3: ``` isTrue: boolean -> boolean isTrue x = x == true ``` 4 - 7: ``` isTrue: boolean -> boolean isTrue x = x != true ```
-
Some form of basic type errors
Failed to parse examples/errors/mismatching_types.derw due to: Error on lines 0 - 3 Expected `boolean` but got `number` in the body of the function: ``` isTrue: boolean -> boolean isTrue x = 1 + 2 ``` Error on lines 4 - 7 Expected `List string` but got `List number`: ``` names: List string names = [1..2] ```
-
lambdas
\x -> x + 1
,\x y -> x + y
-
Typescript output
-
Javscript output
-
Elm output
-
Module resolution
-
CLI
-
Basic type checking
-
Detect if types exist in current namespace
-
Syntax highlighting for editors
-
Collision detection for names in a module
-
Importing of Derw files
import "./other" import "./something" as banana import "./another" exposing ( isTrue, isFalse )
-
Errors when failing to find relative import
Warning! Failed to find `examples/derw_imports/banana` as either derw, ts or js
-
Single line comments
-- hello isTrue: boolean -> boolean isTrue x = x
-
Single line comments in function or const bodies
isTrue: boolean -> boolean isTrue x = -- hello x
-
Multiline comments
{- hello world -} isTrue: boolean -> boolean isTrue x = x
-
Function arguments
map: (a -> b) -> a -> b map fn value = fn value
-
Globals
Globals can be accessed through the
globalThis
module which is imported into every namespace. E.gglobalThis.console.log
-
Constant if statements
name: string name = if 1 == 1 then "Noah" else "James"
-
Constant case statements
name: string name = case person of "n" -> "Noah" "j" -> "James" default -> "Other"
-
List prepend
numbers: List number numbers = 1 :: [ 2, 3 ]
-
An automatic formatter with no options
derw format
-
A standard library
-
Support for Coed
Use html
-
Testing support via Bach
Write a file with
_test
as an extension (e.gList_test.derw
).import Test exposing (equals) testMath: boolean -> void testMath a? = equals 1 1
Compile it, then run bach via
npx @eeue56/bach
-
Type checking
-
Benchmarking support via Mainc
-
Async support
-
Packaging
-
Package init
derw init
-
Package testing
# inside a package directory derw test
-
Compile a package
derw compile
-
Install a package
derw install --name derw-lang/stdlib --version main
-
An info command to find out stats about modules
derw init
-
A repl
derw repl
-
Bundling
derw bundle --entry src/Main.derw --output dist/index.js --watch --quiet
-
English output
derw compile --target english
-
Template generation
derw template --path src/Main.derw --template web
- Time travelling debugger
- Type checking with interop with TypeScript
- Derw compiler is written in Derw
- All top level consts or functions must have type definitions
- Format strings ``
- No need for module names in the module file itself. Use
exposing
instead
Currently VSCode syntax highlighting is supported by this extension: https://github.com/eeue56/derw-syntax. It is not on the marketplace because Microsoft account creation was down when I tried.
Instead, you can do:
git clone https://github.com/derw-lang/derw-syntax
cp -r derw-syntax ~/.vscode/extensions/derw-syntax-0.0.1
git clone https://github.com/derw-lang/derw-language-server
cp -r derw-language-server ~/.vscode/extensions/derw-language-server-0.0.1
derw which means oak. Oak is one of the native trees in Wales, famous for it's long life, tall stature, and hard, good quality wood. An English speaker might pronounce it as "deh-ru".