~evanj/zan

A programming language for your fingers.
Feat(ex): Refining example.
Feat(flex+bison): Initial grammar work for bison.
Feat(bison): Using C bison as starting point. Slightly modified.

refs

master
browse  log 

clone

read-only
https://git.sr.ht/~evanj/zan
read/write
git@git.sr.ht:~evanj/zan

You can also use your local clone with git send-email.

THE ZANZIBAR PROGRAMMMING LANGUAGE

A programming languge for your fingers.

MOTIVATION

Zanzibar is the language I wish we had.

There are so many newer programming languages that have brilliant ideas inside
them, but I think they have failed to make them feel familiar to our fingers.

Zan (short for Zanzibar) steals as much of its design as possible from other 
programming languages. If someone else did it really well, why do it any 
differently? As such most of Zan won't feel new. If you've used some of these 
languages before you will probably recognize features of Zan.

There is no compiler or any tools for Zan right now, I hope to someday work
on some. But for now, this is just an exercise in programming language design.

SYNTAX

Zan's syntax should feel compact and effortless to type. There are no semicons,
comments are a two characters forward slash characters, syntax avoid too many 
characters that require shift to type.

Places where syntax could go multiple different ways, I've just picked what
seems most natural for the fingers. It's intended to be easy and fast to type
for all developers.

HELLO WORLD

--------------------------------------------------------------------------------
pkg main // short for "package"

use [ io ]

fn main [] [
  io.print [ "hello world" ]
]
--------------------------------------------------------------------------------
  

COMMENTS

--------------------------------------------------------------------------------
// inline comments only
// combine to make multiline
--------------------------------------------------------------------------------


DECLARATIONS

--------------------------------------------------------------------------------
name = expression
--------------------------------------------------------------------------------


NULL/NIL

--------------------------------------------------------------------------------
missing = nope // only `ptr` type can be nope'able
--------------------------------------------------------------------------------


BOOLEANS

--------------------------------------------------------------------------------
positive = yes
negative = no
--------------------------------------------------------------------------------


STRINGS

--------------------------------------------------------------------------------
plain = "hello world"
interpolated = io.sprint [ "hello", name ]
escapes = "hello \"world\""

multiline = `
  The quick brown fox
  jumped over the lazy dog     
`

multilineWithIndentation = `
  This is indented by 0 spaces.
    This is indented by 2 spaces.
      This is indented by 4 spaces.
`
--------------------------------------------------------------------------------


NUMBERS

--------------------------------------------------------------------------------
someInt = 4
someFloat = 4.14
largeNumber = 98_521_391_124
--------------------------------------------------------------------------------


LISTS

--------------------------------------------------------------------------------
things = [ 1 2 3 ]

otherThings = [
  1
  2
  3
]

someItem = things[2]
someList = things[1:2]
--------------------------------------------------------------------------------


MAPS

--------------------------------------------------------------------------------
someMap = map [
  "key1" "value1"
  "key2" "value2"
}

otherMap = map [
  1 "one"
  2 "two"
]
--------------------------------------------------------------------------------


OPERATORS

--------------------------------------------------------------------------------
// Arithmetic, converted into math ops by compiler.
addition = a + b        // math.add [ a b ]
subtraction = a - b     // math.subtract [ a b ]
division = a / b        // math.divide [ a b ]
multiplication = a * b  // math.multiple [ a b ] 
remainder = a % b       // math.mod [ a b ]
exponentiation = a ** b // math.exp [ a b ]
negation = -a

// Comparison
equality = a == b

lessThan = a < b
lessThan2 = a < b < c // equivalent to `a < b && b < c`
                          // except `b` is only evaluated once
lte = a <= b
lte2 = a <= b <= c
lessThan3 = a <= b < c

greaterThan = a > b
greaterThan2 = a > b > c
gte = a >= b
gte2 = a >= b >= c
greaterThan3 = a >= b > c

// Logical
andish = expr and expr
orish = expr or expr
notish = not expr

// Grouping
either = [a and b] or [c and d]
--------------------------------------------------------------------------------


IF/ELSE

--------------------------------------------------------------------------------
if condition [ callFuncIfTruthy[] ]

if condition [
  doSomethingIfTruthy[]
]
else [
  doSomethingElse[]
]

if condition [
  doSomethingIfTruthy[]
]  
else if condition2 [
  doSomethingElseIf2Truthy[]
] 
else [
  doSomethingElse[]
]
--------------------------------------------------------------------------------


SWITCH/MATCH

--------------------------------------------------------------------------------

// If one branch has a break
// all branches must have a break.
// Operates like a "match"
thing = match someString [
  "evan" [
    break "this is evan"
  ]
  "madison" [
    break "this is madison"
  ]
  def [
    break "not a person I know"
  ]
]

io.print[thing]

// No breaks. Operates like a switch.
// And no automatic fall through.
match someInteger [
  1 [
    io.print[ "got a one" ]
  ]
  def [
    io.print[ "not a one" ]
  ]
]

--------------------------------------------------------------------------------


LOOP

--------------------------------------------------------------------------------
loop x = 0, x < 10, x++ [
  io.print [ "value is" x ]
]

x = 0
loop [
  x++
  if x == 10 [
    break
  ]
]

loop module.condition[] [
  // Loops until `module.condtion[]` returns `false` instead of `true`.
]
  
loop item = things [ 
  io.print [ "one of the items is" item ]
]

--------------------------------------------------------------------------------


FUNCTIONS

--------------------------------------------------------------------------------
fn add [ int a b ] int [
  ret a + b
]

result = add [ 400, 20 ]
--------------------------------------------------------------------------------


DO 

--------------------------------------------------------------------------------
// `someValues` value will be `8`.
someValue = [
  a = 4
  b = 2
  a * b 
]
--------------------------------------------------------------------------------


JUNK

--------------------------------------------------------------------------------
_ = "ignore me"

// `doSomething` is a function that receives a function 
// and calls it with three parameters. Here we are only
// interested in the last.
doSomething [ fn [ int _ _ val ] [
  io.print [ value ]
]]

log[_]
// SyntaxError: "junk" bindings (_) are not valid
// identifiers and cannot be referenced. Give your
// binding a name instead.
--------------------------------------------------------------------------------


BLOCKS

--------------------------------------------------------------------------------
fn dothing [] [
  // block
]

loop thing = things [
  // block
]

if cond [
  // block
]
else if cond [
  // block
]
else [
  // block
]
--------------------------------------------------------------------------------


BLOCK SCOPING

--------------------------------------------------------------------------------
a = 1
if cond {
  a = 2
  b = 3
  io.print [ a ] // a is 2
}
io.print [ a ] // a is 1 
io.print [ b ] // Error! There's no variable named "b" in this scope!
--------------------------------------------------------------------------------


MODULES 

--------------------------------------------------------------------------------
// naming
pkg main // Must be same name as directory unless main.

// importing
use [
  time 
  math
  io
  relative/pkg/thing
]

io.print [ 
  thing.new[] // `relative/pkg/thing` exports `new` function
  time.now[]  // `time` exports `now` function
  math.pi     // `math` exports `pi` value
]

// exporting
fn new [] thing [
  ret thing [ "values go here" ]
]

give [
  new 
]
--------------------------------------------------------------------------------


TYPE ALIAS

--------------------------------------------------------------------------------
type myString string
--------------------------------------------------------------------------------


BASIC TYPES

--------------------------------------------------------------------------------
type myType bool
type myType int
type myType float
type myType string            // string is really a type alias for `byte list`
type myType string list       // a list of strings
type myType ptr byte          // a pointer to a byte
type myType map[ int string ] // int are keys, strings are values
type myType error             // type alias for [ string msg, int code ]
--------------------------------------------------------------------------------


STRUCT TYPES AND METHODS

--------------------------------------------------------------------------------
type myType [
  string name
  int age

  // embedded method
  fn greet [] [
    io.print [ "hello" myType.name ]
  ]
]

// "constructor" / "factory"
fn new [ string name int age ] myType [
  ret myType [ name age ]
]

// traditional method 
fn myType print [] [
  io.print [ 
    "hi, my name is"
    myType.name
    "and my age is"
    myType.age
  ]
]

// Instance scoped as `self`.
// Traditional methods can alias their `this`/`self.`.
fn [ self myType ] birthday [] [
  self.age++
  io.print [ "happy birthday" self.name ]
  io.print [ "you are now" self.age "years old" ]
]
--------------------------------------------------------------------------------


FUNCTIONS

--------------------------------------------------------------------------------

fn thing [ string param1 int param2 ] [
  // ...
]

fn thing [ ...string list args ] [
  // ...
]

fn thing [] string [
  ret "nice"
]
--------------------------------------------------------------------------------


DEFER/LATER AND ANONYMOUS FUNCTIONS

--------------------------------------------------------------------------------
pkg main

use [ io ]

fn main [] [
  later fn [] [ io.print [ "this is executed last" ] ] // defer is the Go equiv
  io.print [ "this is executed first" ]
  fn [] [ io.print [ "this is executed second" ] ] []
]
--------------------------------------------------------------------------------




SPECIAL THANKS

Jamie Kyle @jamiebuilds
https://github.com/jamiebuilds/ghost-lang

The Go Programming Language Specification
https://golang.org/ref/spec